I have a shiny app that is made up of several select widgets. The number of the widgets depends on some data. In this example I use two. However, the user has the option to add or remove select widgets via action buttons.
At the moment it is not possible to clear those select widgets. For example, open the app and remove the second select widget. Afterwards, add another select widget. What happens is that the new select widget still has the old value. But what I want is that the new select widget is empty. I tried to achieve this with updateSelectInput() but it does not work.
I appreciate any help. If you have any suggestions on how to improve the app or make it simpler without losing the functionality I'd love to hear as well about that.
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)
EDIT
I simplified the example in the original post too much so here is an edit. The number of inital widgets depends on the row of a table a user selects. I tried to extend lz100's answer by moving some code from ui to server. However, I failed. See the following code.
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)