rstudio / shiny

Easy interactive web applications with R
https://shiny.posit.co/
Other
5.36k stars 1.87k forks source link

`updateSelectizeInput()` with `server=TRUE` does not work when `render` option is used #3571

Closed GitHunter0 closed 2 years ago

GitHunter0 commented 2 years ago

Dropdown do not appear when server = TRUE if using render option.

MWE:

library(shiny)
library(purrr)

.data <- data.frame(var_name=c("A","B"), var_label = c("A_lab","B_lab")) |>
  purrr::transpose()

ui <- fluidPage(

  theme = bslib::bs_theme(version=4, bootswatch='superhero'),

  # useShinyjs(),  # Set up shinyjs
  shinyjs::useShinyjs(),

  selectizeInput(
    inputId = "in_selectize",
    label = "select variable",
    choices = NULL,
    multiple = TRUE
  ),

  textOutput("out_selectize")

)

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

  shiny::updateSelectizeInput(
    inputId='in_selectize',
    label = "updated choices",
    options = list(
      options = .data,
      valueField = 'var_name',
      labelField = c('var_name'),
      render = I("{
        option: function(item, escape) {
          return '<div>'
            + '<strong>' + escape(item.var_name) + '</strong>'
            + '<br>'
            + escape(item.var_label)
            + '</div>';
        }
      }")
    ),
    server = TRUE
  )

  output$out_selectize <-
    shiny::renderText(input$in_selectize)  

}

shiny::shinyApp(ui, server)
R version 4.1.1 (2021-08-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19044)

Matrix products: default

locale:
[1] LC_COLLATE=English_United States.1252 
[2] LC_CTYPE=English_United States.1252   
[3] LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C                          
[5] LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods  
[7] base     

other attached packages:
[1] purrr_0.3.4 shiny_1.7.1

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.7        bslib_0.3.1       compiler_4.1.1   
 [4] pillar_1.6.4      later_1.3.0       jquerylib_0.1.4  
 [7] shinyjs_2.0.0     tools_4.1.1       digest_0.6.28    
[10] evaluate_0.14     viridisLite_0.4.0 jsonlite_1.7.2   
[13] lifecycle_1.0.1   tibble_3.1.5      gtable_0.3.0     
[16] pkgconfig_2.0.3   rlang_0.4.11      DBI_1.1.1        
[19] yaml_2.2.1        xfun_0.27         fastmap_1.1.0    
[22] knitr_1.36        duckdb_0.3.1-1    httr_1.4.2       
[25] dplyr_1.0.7       fs_1.5.0          htmlwidgets_1.5.4
[28] generics_0.1.0    sass_0.4.0        vctrs_0.3.8      
[31] tidyselect_1.1.1  grid_4.1.1        glue_1.4.2       
[34] data.table_1.14.0 R6_2.5.1          fansi_0.5.0      
[37] plotly_4.9.4.1    rmarkdown_2.11    tidyr_1.1.4      
[40] ggplot2_3.3.5     magrittr_2.0.1    scales_1.1.1     
[43] promises_1.2.0.1  ellipsis_0.3.2    htmltools_0.5.2  
[46] assertthat_0.2.1  mime_0.12         xtable_1.8-4     
[49] colorspace_2.0-2  httpuv_1.6.3      utf8_1.2.2       
[52] lazyeval_0.2.2    munsell_0.5.0     cachem_1.0.6     
[55] crayon_1.4.1 
etiennebr commented 2 years ago

@GitHunter0, you need to pass .data as a data.frame to choices.

library(shiny)
library(purrr)

.data <- data.frame(var_name=c("A","B"), var_label = c("A_lab","B_lab")) 

ui <- fluidPage(
  selectizeInput(
    inputId = "in_selectize",
    label = "select variable",
    choices = NULL,
    multiple = TRUE
  ),
  textOutput("out_selectize")
)
server <- function(input, output, session) {

  shiny::updateSelectizeInput(
    inputId='in_selectize',
    label = "updated choices",
    choices = .data,
    options = list(
      valueField = 'var_name',
      labelField = 'var_name',
      render = I("{
        option: function(item, escape) {
          return '<div>'
            + '<strong>' + escape(item.var_name) + '</strong>'
            + '<br>'
            + escape(item.var_label)
            + '</div>';
        }
      }")
    ),
    server = TRUE
  )
  output$out_selectize <- shiny::renderText(input$in_selectize)  
}

shiny::shinyApp(ui, server)
GitHunter0 commented 2 years ago

@etiennebr , thanks man! That detail solved the issue.

bradybray commented 1 year ago

@GitHunter0, you need to pass .data as a data.frame to choices.

library(shiny)
library(purrr)

.data <- data.frame(var_name=c("A","B"), var_label = c("A_lab","B_lab")) 

ui <- fluidPage(
  selectizeInput(
    inputId = "in_selectize",
    label = "select variable",
    choices = NULL,
    multiple = TRUE
  ),
  textOutput("out_selectize")
)
server <- function(input, output, session) {

  shiny::updateSelectizeInput(
    inputId='in_selectize',
    label = "updated choices",
    choices = .data,
    options = list(
      valueField = 'var_name',
      labelField = 'var_name',
      render = I("{
        option: function(item, escape) {
          return '<div>'
            + '<strong>' + escape(item.var_name) + '</strong>'
            + '<br>'
            + escape(item.var_label)
            + '</div>';
        }
      }")
    ),
    server = TRUE
  )
  output$out_selectize <- shiny::renderText(input$in_selectize)  
}

shiny::shinyApp(ui, server)

I know this is old, but I wanted to point out the Shiny docs make no reference to a dataframe being a required argument to choices when server=TRUE. It makes mention of passing a list. Maybe I'm being nitpicky but shouldn't the docs note this?

Bray.

gadenbuie commented 1 year ago

I think the key insight from @etiennebr is that the initial UI has choices = NULL, so @GitHunter0 had to include choices = .data in the updateSelectizeInput() call to populate the choices. I don't think there's a requirement that choices be a dataframe when server = TRUE.