I can't select or unselect using updateSelectizeInput with multiple choices

When I use updateSelectizeInput on the server and selectizeInput in ui, to choose multiple options from a table that I will filter by those options, Shiny shows all selections in the selection box, but I can't delete any or choose a subset of options, as it automatically updates to all options. The data comes from a reactive(), that's why I have to use updateSelectizeInput.

This is not a reprex, but represents the relationship between the variables and the codes involved:

ui <- fluidPage(navbarPage(
tabPanel("Resultados",
           fluidRow(selectizeInput("muestra_selec",
                                "Seleccione las muestras que desea incluir en el informe:",
                                multiple = TRUE,
                                choices = NULL,
                                selected = NULL,
                                width = NULL)),
           hr(),
           navlistPanel("Resultados",
                        widths = c(2,10),
                        tabPanel("LCM",
                                 mainPanel(tableOutput("lcm"))),
                        tabPanel("BTEX",
                                 mainPanel(
                                   tabsetPanel(type = "tabs",
                                               tabPanel("Datos BTEX + Control Calidad",
                                                        DT::dataTableOutput("datos_btex_control",
                                                                            width = "150%")),
                                               tabPanel("Tabla Informe BTEX",
                                                        DT::dataTableOutput("Resultados_btex",
                                                                            width = "150%")))))
)))

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

output$Resultados_btex <- DT::renderDataTable({
    
    resultados <- resultados_btex()
    
    # Permite seleccionar datos que estan en server.
    
    updateSelectizeInput(session,
                      "muestra_selec",
                      choices = unique(resultados$`Muestra`),
                      selected = unique(resultados$`Muestra`))
    
    resultados2 <- resultados %>% dplyr::filter(resultados$`Muestra` %in% input$`muestra_selec`)
  
    DT::datatable(data = resultados2,
                  extensions = c('Buttons',
                                 'Scroller',
                                 'AutoFill',
                                 'RowGroup'),
                  options = list(pageLength = 20,
                                 autoWidth = TRUE,
                                 deferRender = FALSE,
                                 scrollY = 500,
                                 scrollX = TRUE,
                                 scroller = TRUE,   
                                 dom = 'Bfrtip',
                                 buttons = c('copy', 'excel','pdf'),
                                 autoFill = TRUE,
                                 rowGroup = list(dataSrc = 0)),
                  rownames = FALSE,
                  filter = 'top',
                  caption = 'Tabla de BTEX para Informe')
  })

}

This is the complete list of options, when I try to remove one or more, the whole list is re-selected.

image

As a general rule dont use update* functions within render* functions.

Thank you.

I removed the update* function from the render* function and put it inside a reactive(), but I still have the same problem. I can't choose which choise to use as it automatically re-selects all the options.

When I put selected = NULL in the updateSelectInput function, when I choose an option from the list, it automatically leaves me blank.

resultados_btex <- reactive({
    
    resultados <- resultados_lcm()
    
    ## Filtra blancos y duplicados
    
    nombres_duplicado <- c("Duplicado","duplicado", "Duplicado de campo")
    nombres_blanco_terreno <- c("Blanco de terreno", "Blanco de campo")
    
    resultados <- dplyr::filter(resultados, !grepl(paste(nombres_blanco_terreno,collapse = "|"),`Tipo de muestra terreno`))
    
    resultados <- dplyr::filter(resultados, !grepl(paste(nombres_duplicado,collapse = "|"), `Tipo de muestra terreno`))
    
    lcm <- lcm()
    
    lcm <- lcm %>% 
      filter(Parametro == c("BENZENE","TOLUENE","ETHYL BENZENE","m-p XILENE","o- XILENE")) %>% 
      select(`Parametro`,`CAS#`)
    
    resultados <- resultados %>% mutate("Unidad" = "[\u00b5g/m\u00b3]")
    resultados <- left_join(resultados,lcm)
    resultados <- resultados %>% select(Muestra,`ID muestra`,Parametro,`CAS#`,Unidad,Concentracion,`Concentracion Normalizada`,Conc_reporte,LCM)
    resultados <- distinct(resultados)
    
    updateSelectInput(getDefaultReactiveDomain(),
                      "muestra_selec",
                      choices = unique(resultados$`Muestra`),
                      selected = NULL)
    
    resultados <- resultados %>% dplyr::filter(resultados$`Muestra` %in% input$`muestra_selec`)
    
    resultados
    
  })

Since the data comes from a reactive, you can move the selectizeInput into a renderUI() in the server and call it in the ui with uiOutput(). In this setup, updateSelectizeInput is not necessary.

ui <- fluidPage(navbarPage(
  tabPanel("Resultados",
           fluidRow(uiOutput('muestraSelec')),
           hr(),
           navlistPanel("Resultados",
                        widths = c(2,10),
                        tabPanel("LCM",
                                 mainPanel(tableOutput("lcm"))),
                        tabPanel("BTEX",
                                 mainPanel(
                                   tabsetPanel(type = "tabs",
                                               tabPanel("Datos BTEX + Control Calidad",
                                                        DT::dataTableOutput("datos_btex_control",
                                                                            width = "150%")),
                                               tabPanel("Tabla Informe BTEX",
                                                        DT::dataTableOutput("Resultados_btex",
                                                                            width = "150%")))))
                        )))
  )
  
  server <- function(input, output, session) {
    
    output$muestraSelec = renderUI({
      
      selectizeInput("muestra_selec",
                     "Seleccione las muestras que desea incluir en el informe:",
                     multiple = TRUE,
                     choices = resultados_btex()$`Muestra`,
                     selected = NULL,
                     width = NULL)
    
      })
    
    output$Resultados_btex <- DT::renderDataTable({
      
      resultados2 <- resultados_btex() %>% 
        dplyr::filter(`Muestra` %in% input$`muestra_selec`)
      
      DT::datatable(data = resultados2,
                    extensions = c('Buttons',
                                   'Scroller',
                                   'AutoFill',
                                   'RowGroup'),
                    options = list(pageLength = 20,
                                   autoWidth = TRUE,
                                   deferRender = FALSE,
                                   scrollY = 500,
                                   scrollX = TRUE,
                                   scroller = TRUE,   
                                   dom = 'Bfrtip',
                                   buttons = c('copy', 'excel','pdf'),
                                   autoFill = TRUE,
                                   rowGroup = list(dataSrc = 0)),
                    rownames = FALSE,
                    filter = 'top',
                    caption = 'Tabla de BTEX para Informe')
    })
    
  }

Hola Camilo!

I just wanted to chime in to shed a bit of light on the odd behavior you found.
Maybe you already solved this issue, but aside from what it is pointed out in the other replies, I think one main issue is that you are using input$muestra_selec(by the way, you don't need to wrap this variable name around ``) inside the same reactive expressions (DT::renderDataTable and resultados_btex in your respective examples) where you call the updateSelectizeInput.

So, when the user selects a value, this will trigger the whole reactive expression because input$muestra_selec changed. This reactive expression aside from the data calculations also will update the selectize input options and selected value (i.e., input$muestra_selec), which will then again trigger the execution of the whole reactive expression.

Depending on how you expect the app to work, this could be avoided by extracting the updating to react to changes in the data.

If you want to discuss further, feel free to drop me a line or to provide a bit more of context on how you envision reactivity in your app.

Hope this helps!
Cheers,
Agus


This post was published by an Appsilon team member. Our company can help you get the most out of RShiny and Posit/RStudio products.

Check our open positions here.

Appsilon: Building impactful RShiny Dashboards and providing R coding services.
Appsilon_GIFsmall_whitebg