【问题标题】:How to clear dynamic UI elements?如何清除动态 UI 元素?
【发布时间】:2022-01-18 01:13:20
【问题描述】:

我有一个闪亮的应用程序,它由几个选定的小部件组成。小部件的数量取决于一些数据。在这个例子中,我使用了两个。但是,用户可以选择通过操作按钮添加或删除选择小部件。

目前无法清除这些选择小部件。例如,打开应用程序并删除第二个选择小部件。之后,添加另一个选择小部件。发生的情况是新的选择小部件仍然具有旧值。但我想要的是新的选择小部件是空的。我尝试使用updateSelectInput() 来实现这一点,但它不起作用。

感谢您的帮助。如果您对如何改进应用程序或使其更简单而不丢失功能有任何建议,我也很乐意听到。

library(shiny)

data <- data.frame(A = c("a", "b"))

ui <- fluidPage(
  fluidRow(
    column(
      width = 6,
      uiOutput("ui_output_A")
    ),
  ),
  fluidRow(
    column(
      width = 6,
      uiOutput("ui_button_add"),
    ),
    column(
      width = 6,
      uiOutput("ui_button_remove")
    )
  )
)

server <- function(input, output, session) {
  widget_counter <- reactiveValues(value = 1)
  
  if (nrow(data) > 1) {
    widget_counter$value <- nrow(data)
  } else {
    widget_counter$value <- 1
  }
  
  output$ui_button_add <- renderUI({
    actionButton("button_add",
                 label = "Add")
  })
  
  output$ui_button_remove <- renderUI({
    actionButton("button_remove",
                 label = "Remove")
  })
  
  observeEvent(input$button_add, {
    widget_counter$value <- widget_counter$value + 1
  })
  
  observeEvent(input$button_remove, {
    if (widget_counter$value > 0) {
      updateSelectInput(
        session = session,
        inputId = paste0("selectt_A_",
                         widget_counter$value),
        selected = NA
      )
      widget_counter$value <- widget_counter$value - 1
    }
  })
  
  all_inputs <- reactive({
    x <- reactiveValuesToList(input)
  })
  
  reactive_A <- reactive({
    n <- widget_counter$value
    if (n > 0) {
      isolate({
        lapply(seq_len(n), function(i) {
          selectInput(inputId = paste0("select_A_", i),
                      label = paste0(i, ".) A:"),
                      choices = as.list(c("", "a", "b", "c", "d")),
                      selected =
                        if (isTRUE(i <= nrow(data))) {
                          data[i, "A"]
                        } else {
                          all_inputs()[[paste0("select_A_", i)]]
                        }
          )
        })
      })
    }
  })
  
  output$ui_output_A <- renderUI({reactive_A()})
}

shinyApp(ui, server)

编辑

我对原始帖子中的示例进行了过多的简化,因此这里进行了修改。初始小部件的数量取决于用户选择的表格行。我试图通过将一些代码从 ui 移动到服务器来扩展 lz100 的答案。然而,我失败了。请参阅以下代码。

library(shiny)
library(DT)
library(spsUtil)

data1 <- data.frame(id = c(1, 1, 2), 
                    value = c("a", "b", "a"))
data2 <- data.frame(id = 1:2)

ui <- fluidPage(
  fluidRow(
    DTOutput("table_output")
  ), 
  fluidRow(
    column(
      width = 6,
      uiOutput("ui_output")
    )
  ),
  fluidRow(
    column(
      width = 6,
      actionButton("button_add",
                   label = "Add"),
    ),
    column(
      width = 6,
      actionButton("button_remove",
                   label = "Remove")
    )
  )
)

server <- function(input, output, session) {
  counter <- reactiveValues(value = 1)
  
  output$table_output <- renderDT(datatable(data2))
  
  observeEvent(input$table_output_rows_selected, { 
    if (length(which(data1[, "id"] == data2[input$table_output_rows_selected, "id"])) > 1) {
      counter$value <- length(which(data1[, "id"] == data2[input$table_output_rows_selected, "id"]))
    } else {
      counter$value <- 1
    }
  })
  
  output$ui_output <- renderUI({
    div(
      id = "input_els",
      # define some default inputs, here 2 default inputs
      # when user wants to add more, we do it from server
      lapply(seq_len(counter$value), function(i) {
        div(
          id = paste0("select_container", i),
          selectInput(paste0("select_", i),
                      label = paste0(i, ".):"),
                      choices = as.list(c("", letters)),
                      selected =
                        if (isTRUE(i <= length(which(data1[, "id"] == data2[input$table_output_rows_selected, "id"])))) {
                          data1[i, "value"]
                        } else {
                          NA
                        }
          )
        )
        
      })
    )
  })
  
  observeEvent(input$button_add, {
    insertUI(
      "#input_els", 
      ui = div(
        id = paste0("select_container", counter$value + 1),
        selectInput(
          paste0("select_", counter$value + 1),
          paste0(counter$value + 1, ".) "),
          c("", "a", "b", "c", "d")
        )   
      )      
    )
    inc(counter$value)
  })
  observeEvent(input$button_remove, {
    req(counter$value > 0)
    removeUI(paste0("#select_container", counter$value))
    inc(counter$value, -1)
  })
}

shinyApp(ui, server)

【问题讨论】:

    标签: r shiny


    【解决方案1】:
    library(shiny)
    library(spsUtil)
    data <- data.frame(A = c("a", "b"))
    n <- 2
    ui <- fluidPage(
        fluidRow(
            column(
                width = 6,
                div(
                    id = "input_els",
                    # define some default inputs, here 2 default inputs
                    # when user wants to add more, we do it from server
                    lapply(seq_len(n), function(i) {
                        div(
                            id = paste0("select_container", i),
                            selectInput(paste0("select_", i),
                                        label = paste0(i, ".):"),
                                        choices = as.list(c("", "a", "b", "c", "d")),
                                        selected =
                                            if (isTRUE(i <= nrow(data))) {
                                                data[i, "A"]
                                            } else {
                                                all_inputs()[[paste0("select_A_", i)]]
                                            }
                            )
                        )
    
                    })
                )
            )
        ),
        fluidRow(
            column(
                width = 6,
                actionButton("button_add",
                             label = "Add"),
            ),
            column(
                width = 6,
                    actionButton("button_remove",
                                 label = "Remove")
            )
        )
    )
    
    server <- function(input, output, session) {
        counter <- reactiveValues(value = n)
        observeEvent(input$button_add, {
            insertUI(
                "#input_els", 
                ui = div(
                    id = paste0("select_container", counter$value + 1),
                    selectInput(
                        paste0("select_", counter$value + 1),
                        paste0(counter$value + 1, ".) "),
                        c("", "a", "b", "c", "d")
                    )   
                )      
            )
            inc(counter$value)
        })
        observeEvent(input$button_remove, {
            req(counter$value > 0)
            removeUI(paste0("#select_container", counter$value))
            inc(counter$value, -1)
        })
    }
    
    shinyApp(ui, server)
    

    我已经简化了你的代码,让它更加闪亮。看看服务器代码有多干净。

    1. 我们直接从 UI 进行一些默认输入。您知道它们会在开始时出现的输入。
    2. 使用insertUIremoveUI 动态添加/删除其他输入。
    3. 要在selectInput 等输入表单中添加removeUI,最简单的方法是将其包装在另一个div 中。

    编辑

    library(shiny)
    library(DT)
    library(spsUtil)
    
    data1 <- data.frame(id = c(1, 1, 2), 
                        value = c("a", "b", "a"))
    data2 <- data.frame(id = 1:2)
    
    ui <- fluidPage(
        fluidRow(
            DTOutput("table_output")
        ), 
        fluidRow(
            column(
                width = 6,
                uiOutput("ui_output")
            )
        ),
        fluidRow(
            column(
                width = 6,
                actionButton("button_add",
                             label = "Add"),
            ),
            column(
                width = 6,
                actionButton("button_remove",
                             label = "Remove")
            )
        )
    )
    
    server <- function(input, output, session) {
        counter <- reactiveValues(value = 1)
        
        output$table_output <- renderDT(datatable(data2))
        
        observeEvent(input$table_output_rows_selected, { 
            if (length(which(data1[, "id"] %in% data2[input$table_output_rows_selected, "id"])) > 1) {
                counter$value <- length(which(data1[, "id"] %in% data2[input$table_output_rows_selected, "id"]))
            } else {
                counter$value <- 1
            }
        })
        
        output$ui_output <- renderUI({
            div(
                id = "input_els",
                # define some default inputs, here 2 default inputs
                # when user wants to add more, we do it from server
                lapply(seq_len(isolate(counter$value)), function(i) {
                    div(
                        id = paste0("select_container", i),
                        selectInput(paste0("select_", i),
                                    label = paste0(i, ".):"),
                                    choices = as.list(c("", letters)),
                                    selected =
                                        if (isTRUE(i <= length(which(data1[, "id"] %in% data2[input$table_output_rows_selected, "id"])))) {
                                            data1[i, "value"]
                                        } else {
                                            NA
                                        }
                        )
                    )
                    
                })
            )
        })
        
        observeEvent(input$button_add, {
            insertUI(
                "#input_els", 
                ui = div(
                    id = paste0("select_container", counter$value + 1),
                    selectInput(
                        paste0("select_", counter$value + 1),
                        paste0(counter$value + 1, ".) "),
                        c("", "a", "b", "c", "d")
                    )   
                )      
            )
            inc(counter$value)
        })
        observeEvent(input$button_remove, {
            req(counter$value > 0)
            removeUI(paste0("#select_container", counter$value))
            inc(counter$value, -1)
        })
    }
    
    shinyApp(ui, server)
    

    【讨论】:

    • 感谢您的精彩回答。不幸的是,我过于简化了我的例子。您定义为n 的内容实际上应该取决于用户的选择,因此我认为必须将一些代码移至服务器。我根据您的回答尝试了一种方法,但失败了。我将它添加到我的原始帖子中。您知道如何实现这一目标吗?
    • 在上面查看我的编辑
    • 非常感谢。
    猜你喜欢
    • 2015-11-24
    • 1970-01-01
    • 2012-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-25
    • 2018-04-05
    • 1970-01-01
    相关资源
    最近更新 更多