Как добавить / удалить поля ввода динамически с помощью кнопки в блестящей

Я пытался найти решение, как добавить и удалить поля ввода с помощью кнопки в блестящей. У меня нет исходного кода, так как я не достиг такого большого прогресса, но этот пример jQuery ( http://www.mkyong.com/jquery/how-to-add-remove-textbox-dynamically-with-jquery/) дает хорошее представление о том, чего я пытаюсь достичь. Это возможно в Блестящем или я должен использовать блестящий, чтобы сделать это? Заранее спасибо!

3 ответа

Решение

РЕДАКТИРОВАТЬ: я прочитал пример jQuery немного больше, и добавил фрагмент кода, делая то, что я думаю, что вы искали.

Я не знаю, jQuery, поэтому я не мог многое сделать из примера ссылки. Я угадал, что вы хотели, но я думаю, что ключевая идея заключается в использовании renderUI а также uiOutput даже если мое предложение здесь не соответствует действительности.

Чтобы переключить элемент пользовательского интерфейса:

Если вы специально не хотите использовать shinyjsВы могли бы сделать что-то вроде этого:

library(shiny)

ui <- shinyUI(fluidPage(

  actionButton("btn", "Toggle Textbox"),

  textOutput("btn_val"),
  uiOutput("textbox_ui")

))

server <- shinyServer(function(input, output, session) {

  output$btn_val <- renderPrint(print(input$btn))

  textboxToggle <- reactive({

    if (input$btn %% 2 == 1) {
      textInput("textin", "Write something:", value = "Hello World!")
    }

  })

  output$textbox_ui <- renderUI({ textboxToggle() })

})

shinyApp(ui, server)

Чтобы добавить и удалить элементы:

Прочитав немного примера jQuery, я думаю, что это похоже на то, что вы искали:

library(shiny)

ui <- shinyUI(fluidPage(

  sidebarPanel(

      actionButton("add_btn", "Add Textbox"),
      actionButton("rm_btn", "Remove Textbox"),
      textOutput("counter")

    ),

  mainPanel(uiOutput("textbox_ui"))

))

server <- shinyServer(function(input, output, session) {

  # Track the number of input boxes to render
  counter <- reactiveValues(n = 0)

  observeEvent(input$add_btn, {counter$n <- counter$n + 1})
  observeEvent(input$rm_btn, {
    if (counter$n > 0) counter$n <- counter$n - 1
  })

  output$counter <- renderPrint(print(counter$n))

  textboxes <- reactive({

    n <- counter$n

    if (n > 0) {
      lapply(seq_len(n), function(i) {
        textInput(inputId = paste0("textin", i),
                  label = paste0("Textbox", i), value = "Hello World!")
      })
    }

  })

  output$textbox_ui <- renderUI({ textboxes() })

})

shinyApp(ui, server)

Проблема с этим подходом состоит в том, что каждый раз, когда вы нажимаете кнопку добавления или удаления, все поля ввода перерисовываются. Это означает, что любой вклад, который вы могли иметь для них, исчезает.

Я думаю, что вы могли бы обойти это, также сохраняя текущие значения ввода полей ввода в reactiveValues объекта и установки значений из объекта в качестве начальных значений повторно отображаемых полей ввода с помощью value вариант в textInput, Я оставлю реализацию этого пока что.

Спасибо @Mikko Marttila за ответ. Я смог использовать это для своих целей. Кроме того, обращаясь к проблеме повторного рендеринга всех полей ввода, я нашел решение, работающее на этом ответе. Вы можете сохранить все пользовательские данные, используяreactiveValuesToList(), затем вызовите реактивный список, чтобы установить каждое значение для соответствующего ввода пользователя в lapply() заявление.

library(shiny)

ui <- shinyUI(fluidPage(

  sidebarPanel(

    actionButton("add_btn", "Add Textbox"),
    actionButton("rm_btn", "Remove Textbox"),
    textOutput("counter")

  ),

  mainPanel(uiOutput("textbox_ui"))

))

server <- shinyServer(function(input, output, session) {

  # Track the number of input boxes to render
  counter <- reactiveValues(n = 0)

  # Track all user inputs
  AllInputs <- reactive({
    x <- reactiveValuesToList(input)
  })

  observeEvent(input$add_btn, {counter$n <- counter$n + 1})
  observeEvent(input$rm_btn, {
    if (counter$n > 0) counter$n <- counter$n - 1
  })

  output$counter <- renderPrint(print(counter$n))

  textboxes <- reactive({

    n <- counter$n

    if (n > 0) {
      isolate({
        lapply(seq_len(n), function(i) {
          textInput(inputId = paste0("textin", i),
                    label = paste0("Textbox", i), 
                    value = AllInputs()[[paste0("textin", i)]])
        })
      })
    }

  })

  output$textbox_ui <- renderUI({ textboxes() })

})

shinyApp(ui, server)

РЕДАКТИРОВАТЬ: я завернулlapply() заявление в isolate() потому что это раздражает, когда поля повторно отрисовываются, когда вы пытаетесь ввести в поле

Вместо того, чтобы повторно отображать весь список входных данных, попробуйте следующее

Я отслеживаю все созданные файлы, удаляю последний созданный и повторно используюidsиз удаленных. Я начинаю с начального поля (в этом нет реальной необходимости, но я предполагаю, что в реальном сценарии работы вы ожидаете, что по крайней мере 1 текстовое поле появится и увеличится после этого). Начать работу без начального поля просто.

Кроме того, я слежу за значениямиtextInputящики, которые в данный момент активны, в реактивном списке. Вам это точно понадобится

Наконец, я думаю, для двоихreactiveValuesУ меня есть [insertedиcounter], один из них, возможно, лишний, но эй...

Надеюсь, поможет!

      library(shiny)

ui <- fluidPage(

  actionButton("insertBtn", "Insert"),
  actionButton("deleteBtn", "Delete"),
  h4("My boxes"),
  # Initial box here to start with. Not needed but it is nice to have one :)
  div(id = "box-1", textInput(inputId =  "box-1", label = "box-1")),
  div(id = "placeholder"),
  h4('Box contents'),
  verbatimTextOutput("my_inputs")
)

server <- function(input, output, session) {
  
  ## keep track of elements inserted and a counter of the elements
  rv <- reactiveValues(
    inserted = c("box-1"),
    counter = 1
  )
  
  observeEvent(input$insertBtn, {
    
    rv$counter <- rv$counter+1
    serial <- rv$counter
    id <- paste0('box-', serial)
    rv$inserted <- c(rv$inserted, id)
    
    insertUI(
  
      selector = '#placeholder',      
      ## wrap element in a div with id for ease of removal
      ui = div(id = id,
               textInput(inputId =  id, label = paste0("box-", serial))
      )
    )
      
  })
  
  observeEvent(input$deleteBtn, { 
    req(rv$counter>0) 
    # removes the last one 
    id_to_remove <- rv$inserted[length(rv$inserted)]
    
    removeUI(
      ## pass it in as JQuery selector
      selector = paste0('#', id_to_remove)
    )
    
    rv$inserted <- rv$inserted[-length(rv$inserted)]
    
    rv$counter <- rv$counter - 1
    
  })
  
  my_inputs <- reactive({
    
    req(rv$inserted) # need to have some inputs
    
    l <- reactiveValuesToList(input)
    
    # regex of the union of all inputs. Note the starting input box-1
    ids_regex <- paste(c("box-1", rv$inserted), collapse = "|")
    
    l[grepl(ids_regex, names(l))]
    
  })
  
  output$my_inputs <- renderPrint({
    
    my_inputs()
    
  })
  
  
}

shinyApp(ui, server)

Большое спасибо

этот пост и этот и эти ТАК посты раз , два

Другие вопросы по тегам