【问题标题】:Reset input fields of dynamically generated widgets through insertUI通过 insertUI 重置动态生成的小部件的输入字段
【发布时间】:2019-08-17 11:19:23
【问题描述】:

我正在尝试开发一个闪亮的应用程序,它是更大表单的一部分。特别是,对于这个模块,用户可以动态添加(通过 insertUI)和删除(通过 removeUI)具有与前一个完全相同的小部件的新行。此外,每个新的小部件都将包含与前一行的小部件完全相同的选择,感谢Eli Berkow 找到了最后一个功能的解决方案。

理想情况下,用户提交答案后,将调用 shinyjs 包中的 reset() 函数,该函数位于 observeEvent() 中,以重置每个字段的输入。 这适用于“静态”小部件(本示例中未包含),但我找不到重置动态生成小部件的输入字段的方法。

我尝试将每一行分配给不同的div(),并在observeEvent() 中使用for 循环来重置每个div() 中存在的输入,但只清理了一些字段。此外,理想情况下,如果按钮不仅可以重置字段,还可以删除用户添加的每一行并从 0 重新开始计数。下面有一些代码,其中插入了 Reset Button用户界面,但仍然没有任何功能。


library(shiny)
library(shinyjs)

###= UI
ui <- fluidPage(

  br(),

  useShinyjs(),

  br(),

  fluidRow(
    column(width = 3,
           align = "center",
           h5("Letters")
    ),
    column(width = 3,
           align = "center",
           h5("Numbers")
    )
  ),

  br(),

  fluidRow(
    column(width = 12,
           tags$div(id = "amr_test_placeholder")
    )
  ),

  fluidRow(

    br(),
    # "+" and "-" buttons
    column(width = 12,
           actionButton(inputId = "add_amr_test",
                        label = icon(name = "plus",
                                     lib = "font-awesome")),
           actionButton(inputId = "remove_amr_test",
                        label = icon(name = "times",
                                     lib = "font-awesome")),
           actionButton(inputId = "reset_button",
                        label = "RESET FIELDS")
    )
  ),

  br(),
  br(),

  fluidRow(
    column(width = 6,
           tableOutput(outputId = "show_table")
    )
  )

)

###= SERVER
server <- function(input, output, session) {

  observe({

    toggleState(id = "remove_amr_test",
                condition = input$add_amr_test >= input$remove_amr_test)

  })



  amr_test_values <- reactiveValues(val = 0,
                                    ignore = 0)


  ### Defined the input number to count every row
  input_number <- reactive({

    input_number <- input$add_amr_test - input$remove_amr_test + 1

    return(input_number)

  })




  observeEvent(input$add_amr_test, {

    amr_test_divId <- length(amr_test_values$val) + 1

    ###= Animal species
    if (!is.null(eval(parse(text = paste0("input$letters_", input_number() - 1))))) {

      letters_value = eval(parse(text = paste0("input$letters_", input_number() - 1)))

    } else {

      letters_value = ""

    }

    ###= Animal sample type
    if (!is.null(eval(parse(text = paste0("input$numbers_", input_number() - 1))))) {

      numbers_value = eval(parse(text = paste0("input$numbers_", input_number() - 1)))

    } else {

      numbers_value = ""

    }

    ###= Insert dynamic UI
    insertUI(
      selector = "#amr_test_placeholder",
      where = "beforeBegin",
      ui = tags$div(id = amr_test_divId,
                    tags$head(tags$style(HTML(".shiny-split-layout > div {overflow: visible;}"))),

                    br(),

                    fluidRow(
                      column(width = 3,
                             splitLayout(cellWidths = c("18%", "82%"),
                                         h5(paste0(input_number(), ". ")),
                                         selectizeInput(inputId = paste0("letters_",
                                                                         input_number()),
                                                        label =  NULL,
                                                        choices = c("A" = "",
                                                                    "A",
                                                                    "B",
                                                                    "C",
                                                                    "D",
                                                                    "E",
                                                                    "F",
                                                                    "F"),
                                                        selected = letters_value,
                                                        width = "100%",
                                                        options = list(create = TRUE))
                             )
                      ),
                      column(width = 3,
                             selectizeInput(inputId = paste0("numbers_",
                                                             input_number()),
                                            label = NULL,
                                            choices = list("1" = "",
                                                           "1" = "1",
                                                           "2" = "2",
                                                           "3" = "3",
                                                           "4" = "4",
                                                           "5" = "5"),
                                            selected = numbers_value,
                                            width = "100%")
                      )
                    )
      )
    )

    amr_test_values$val <- c(amr_test_values$val,
                             amr_test_divId)

  }, ignoreNULL = FALSE)

  ###= Remove dynamic UI
  observeEvent(input$remove_amr_test, {

    removeUI(

      selector = paste0('#', amr_test_values$val[length(amr_test_values$val)])

    )

    amr_test_values$val <- amr_test_values$val[-length(amr_test_values$val)]

  })






  ###= Dataset to check the dynamic updates of the responses
  response <- reactive({

    if (input_number() != 0) {

      response <- data.frame("Letters" = sapply(X = 1:input_number(),
                                                FUN = function(i) {

                                                  input[[paste0("letters_", i)]]

                                                }),
                             "Numbers" = sapply(X = 1:input_number(),
                                                FUN = function(i) {

                                                  input[[paste0("numbers_", i)]]

                                                })

      )

      return(response)

    } else {

      response <- NULL

    }

  })



  output$show_table <- renderTable({

    response()

  })

}



###= Launch App
shinyApp(ui = ui, server = server)

预期结果可以在以下link看到。

谢谢!

编辑:

Eli Berkow 对我之前版本的问题给出的答案非常有效,因此我将其标记为正确。

我更新了代码,以便了解当应用程序启动时自动显示第一行小部件时 Eli 的脚本应该如何工作。我不明白是否要修改与 reactiveValues 或最后一个 observeEvent 相关的内容。因此,在这个版本的脚本中,我添加了自动显示第一行的功能。什么会适应Eli的代码?

p.s.:我在小部件下添加了一个反应性数据集,以实际查看值的存储方式是否良好(只是检查脚本是否正常工作)。

谢谢!

【问题讨论】:

    标签: r input shiny reset shinyjs


    【解决方案1】:

    见下文:

    library(shiny)
    library(shinyjs)
    
    ###= UI
    ui <- fluidPage(
    
        br(),
    
        useShinyjs(),
    
        br(),
    
        fluidRow(
            column(width = 3,
                   align = "center",
                   h5("Letters")
            ),
            column(width = 3,
                   align = "center",
                   h5("Numbers")
            )
        ),
    
        br(),
    
        fluidRow(
            column(width = 12,
                   tags$div(id = "amr_test_placeholder")
            )
        ),
    
        fluidRow(
    
            br(),
            # "+" and "-" buttons
            column(width = 12,
                   actionButton(inputId = "add_amr_test",
                                label = icon(name = "plus",
                                             lib = "font-awesome")),
                   actionButton(inputId = "remove_amr_test",
                                label = icon(name = "times",
                                             lib = "font-awesome")),
                   actionButton(inputId = "reset_button",
                                label = "RESET FIELDS")
            )
        ),
    
        br(),
        br()
    
    )
    
    ###= SERVER
    server <- function(input, output, session) {
    
        observe({
    
            toggleState(id = "remove_amr_test",
                        condition = input$add_amr_test > input$remove_amr_test + amr_test_values$reset)
    
            toggleState(id = "reset_button",
                    condition = input$add_amr_test > input$remove_amr_test + amr_test_values$reset)
    
        })
    
    
    
        amr_test_values <- reactiveValues(val = 0,
                                          reset = 0)
    
    
        ### Defined the input number to count every row
        input_number <- reactive({
    
            input_number <- input$add_amr_test - input$remove_amr_test - amr_test_values$reset
    
            return(input_number)
    
        })
    
    
    
    
        observeEvent(input$add_amr_test, {
    
            amr_test_divId <- length(amr_test_values$val) + 1
    
            ###= Animal species
            if (!is.null(eval(parse(text = paste0("input$letters_", input_number() - 1))))) {
    
                letters_value = eval(parse(text = paste0("input$letters_", input_number() - 1)))
    
            } else {
    
                letters_value = ""
    
            }
    
            ###= Animal sample type
            if (!is.null(eval(parse(text = paste0("input$numbers_", input_number() - 1))))) {
    
                numbers_value = eval(parse(text = paste0("input$numbers_", input_number() - 1)))
    
            } else {
    
                numbers_value = ""
    
            }
    
            ###= Insert dynamic UI
            insertUI(
                selector = "#amr_test_placeholder",
                where = "beforeBegin",
                ui = tags$div(id = amr_test_divId,
                              tags$head(tags$style(HTML(".shiny-split-layout > div {overflow: visible;}"))),
    
                              br(),
    
                              fluidRow(
                                  column(width = 3,
                                         splitLayout(cellWidths = c("18%", "82%"),
                                                     h5(paste0(input_number(), ". ")),
                                                     selectizeInput(inputId = paste0("letters_",
                                                                                     input_number()),
                                                                    label =  NULL,
                                                                    choices = c("A" = "",
                                                                                "A",
                                                                                "B",
                                                                                "C",
                                                                                "D",
                                                                                "E",
                                                                                "F",
                                                                                "F"),
                                                                    selected = letters_value,
                                                                    width = "100%",
                                                                    options = list(create = TRUE))
                                         )
                                  ),
                                  column(width = 3,
                                         selectizeInput(inputId = paste0("numbers_",
                                                                         input_number()),
                                                        label = NULL,
                                                        choices = list("1" = "",
                                                                       "1" = "1",
                                                                       "2" = "2",
                                                                       "3" = "3",
                                                                       "4" = "4",
                                                                       "5" = "5"),
                                                        selected = numbers_value,
                                                        width = "100%")
                                  )
                              )
                )
            )
    
            amr_test_values$val <- c(amr_test_values$val,
                                     amr_test_divId)
    
        })
    
        ###= Remove dynamic UI
        observeEvent(input$remove_amr_test, {
    
            removeUI(
    
                selector = paste0('#', amr_test_values$val[length(amr_test_values$val)])
    
            )
    
            amr_test_values$val <- amr_test_values$val[-length(amr_test_values$val)]
    
        })
    
        observeEvent(input$reset_button, {
            for(remove_value in 2:max(amr_test_values$val)) {
                removeUI(
    
                    selector = paste0('#', remove_value)
    
                )
            }
    
            amr_test_values$reset <- input$add_amr_test - input$remove_amr_test
            amr_test_values$val <- 0
        })
    
    }
    
    
    ###= Launch App
    shinyApp(ui = ui, server = server)
    

    我在这里添加了一个reset 反应值:

    observe({
    
        toggleState(id = "remove_amr_test",
                    condition = input$add_amr_test > input$remove_amr_test + amr_test_values$reset)
    
        toggleState(id = "reset_button",
                    condition = input$add_amr_test > input$remove_amr_test + amr_test_values$reset)
    
    })
    
    
    
    amr_test_values <- reactiveValues(val = 0,
                                      reset = 0)
    
    
    ### Defined the input number to count every row
    input_number <- reactive({
    
        input_number <- input$add_amr_test - input$remove_amr_test - amr_test_values$reset
    
        return(input_number)
    
    })
    

    然后这个observeEvent:

    observeEvent(input$reset_button, {
        for(remove_value in 2:max(amr_test_values$val)) {
            removeUI(
    
                selector = paste0('#', remove_value)
    
            )
        }
    
        amr_test_values$reset <- input$add_amr_test - input$remove_amr_test
        amr_test_values$val <- 0
    })
    

    更新

    根据您的编辑。

    library(shiny)
    library(shinyjs)
    
    ###= UI
    ui <- fluidPage(
    
      br(),
    
      useShinyjs(),
    
      br(),
    
      fluidRow(
        column(width = 3,
               align = "center",
               h5("Letters")
        ),
        column(width = 3,
               align = "center",
               h5("Numbers")
        )
      ),
    
      br(),
    
      fluidRow(
        column(width = 12,
               tags$div(id = "amr_test_placeholder")
        )
      ),
    
      fluidRow(
    
        br(),
        # "+" and "-" buttons
        column(width = 12,
               actionButton(inputId = "add_amr_test",
                            label = icon(name = "plus",
                                         lib = "font-awesome")),
               actionButton(inputId = "remove_amr_test",
                            label = icon(name = "times",
                                         lib = "font-awesome")),
               actionButton(inputId = "reset_button",
                            label = "RESET FIELDS")
        )
      ),
    
      br(),
      br(),
    
      fluidRow(
        column(width = 6,
               tableOutput(outputId = "show_table")
        )
      )
    
    )
    
    ###= SERVER
    server <- function(input, output, session) {
    
      observe({
    
        toggleState(id = "remove_amr_test",
                    condition = input$add_amr_test > input$remove_amr_test + amr_test_values$reset)
    
        toggleState(id = "reset_button",
                    condition = input$add_amr_test > input$remove_amr_test + amr_test_values$reset)
    
      })
    
    
    
      amr_test_values <- reactiveValues(val = 0,
                                        reset = 0)
    
    
      ### Defined the input number to count every row
      input_number <- reactive({
    
        input_number <- input$add_amr_test - input$remove_amr_test - amr_test_values$reset + 1
    
        return(input_number)
    
      })
    
    
    
    
      observeEvent(input$add_amr_test, {
    
        amr_test_divId <- length(amr_test_values$val) + 1
    
        ###= Animal species
        if (!is.null(eval(parse(text = paste0("input$letters_", input_number() - 1))))) {
    
          letters_value = eval(parse(text = paste0("input$letters_", input_number() - 1)))
    
        } else {
    
          letters_value = "A"
    
        }
    
        ###= Animal sample type
        if (!is.null(eval(parse(text = paste0("input$numbers_", input_number() - 1))))) {
    
          numbers_value = eval(parse(text = paste0("input$numbers_", input_number() - 1)))
    
        } else {
    
          numbers_value = 1
    
        }
    
        ###= Insert dynamic UI
        insertUI(
          selector = "#amr_test_placeholder",
          where = "beforeBegin",
          ui = tags$div(id = amr_test_divId,
                        tags$head(tags$style(HTML(".shiny-split-layout > div {overflow: visible;}"))),
    
                        br(),
    
                        fluidRow(
                          column(width = 3,
                                 splitLayout(cellWidths = c("18%", "82%"),
                                             h5(paste0(input_number(), ". ")),
                                             selectizeInput(inputId = paste0("letters_",
                                                                             input_number()),
                                                            label =  NULL,
                                                            choices = c("A" = "",
                                                                        "A",
                                                                        "B",
                                                                        "C",
                                                                        "D",
                                                                        "E",
                                                                        "F",
                                                                        "F"),
                                                            selected = letters_value,
                                                            width = "100%",
                                                            options = list(create = TRUE))
                                 )
                          ),
                          column(width = 3,
                                 selectizeInput(inputId = paste0("numbers_",
                                                                 input_number()),
                                                label = NULL,
                                                choices = list("1" = "",
                                                               "1" = "1",
                                                               "2" = "2",
                                                               "3" = "3",
                                                               "4" = "4",
                                                               "5" = "5"),
                                                selected = numbers_value,
                                                width = "100%")
                          )
                        )
          )
        )
    
        amr_test_values$val <- c(amr_test_values$val,
                                 amr_test_divId)
    
      }, ignoreNULL = FALSE)
    
      ###= Remove dynamic UI
      observeEvent(input$remove_amr_test, {
    
        removeUI(
    
          selector = paste0('#', amr_test_values$val[length(amr_test_values$val)])
    
        )
    
        amr_test_values$val <- amr_test_values$val[-length(amr_test_values$val)]
    
      })
    
    
      observeEvent(input$reset_button, {
        for(remove_value in 3:max(amr_test_values$val)) {
          removeUI(
    
            selector = paste0('#', remove_value)
    
          )
        }
    
        amr_test_values$reset <- input$add_amr_test - input$remove_amr_test
        amr_test_values$val <- c(0, 2)
      })
    
    
    
      ###= Dataset to check the dynamic updates of the responses
      response <- reactive({
    
        if (input_number() != 0 & !is.null(input[[paste0("letters_", input_number())]])) {
    
          response <- data.frame("Letters" = sapply(X = 1:input_number(),
                                                    FUN = function(i) {
    
                                                      input[[paste0("letters_", i)]]
    
                                                    }),
                                 "Numbers" = sapply(X = 1:input_number(),
                                                    FUN = function(i) {
    
                                                      input[[paste0("numbers_", i)]]
    
                                                    })
    
          )
    
          return(response)
    
        } else {
    
          response <- NULL
    
        }
    
      })
    
    
    
      output$show_table <- renderTable({
    
        response()
    
      })
    
    }
    
    
    
    ###= Launch App
    shinyApp(ui = ui, server = server)
    

    【讨论】:

    • 这个答案可能也适用于您之前的问题。
    • 非常感谢您提供的优雅解决方案!我正在尝试使您的脚本适应重置后必须始终显示小部件的第一(空)行的情况。你认为我应该在 reactiveValues 中进行更改吗?我用新代码编辑了我的问题。再次感谢 Eli,你真的很棒!
    • 见上面的更新。我做了很多改变。请仔细查看并询问是否有任何问题
    • 非常聪明的解决方案 Eli,一如既往的感谢。自从我在这里提出第一个问题以来,我的 UI 发生了一些变化(我真的不需要“删除按钮”,而是每行附近的按钮)。我现在将把你们所有的 cmets 和答案放在一起编辑唯一的“不完整”question。由于发生了一些变化,现在我很确定您也可以回答最后一个问题。非常感谢!
    • 有机会我再试试看
    猜你喜欢
    • 2017-04-26
    • 2014-08-21
    • 1970-01-01
    • 2023-02-10
    • 2014-01-01
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多