shiny icon indicating copy to clipboard operation
shiny copied to clipboard

selectizeInputs can lose their bookmarked values on restoration

Open JohnADawson opened this issue 5 months ago • 8 comments

When an application is bookmarked and restored selectizeInputs can lose their values.

An example follows.

ui <- function(request) {
  shiny::fluidPage(
    shiny::selectizeInput(
      "my_selectize",
      "Selectize",
      character(0L),
      multiple = TRUE,
      options = list(create = TRUE)
    ),
    shiny::verbatimTextOutput("my_text"),
    shiny::bookmarkButton()
  )
}

server <- function(input, output, session) {
  output$my_text <- shiny::renderPrint(input$my_selectize)
}

shiny::shinyApp(ui, server, enableBookmarking = "url")

Run the application.

Image

In the selectizeInput enter "a,b,", so that the input's value is c("a", "b").

Image

Click "Bookmark...".

Image

Restore the application.

Image

The input's value is NULL but ought to be c("a", "b").

The fault was observed when the browser was Firefox 141.0 (64-bit) and sessionInfo() was as follows.

R version 4.3.3 (2024-02-29)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 24.04.2 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so;  LAPACK version 3.12.0

locale:
 [1] LC_CTYPE=en_GB.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_GB.UTF-8        LC_COLLATE=en_GB.UTF-8    
 [5] LC_MONETARY=en_GB.UTF-8    LC_MESSAGES=en_GB.UTF-8   
 [7] LC_PAPER=en_GB.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_GB.UTF-8 LC_IDENTIFICATION=C       

time zone: Europe/London
tzcode source: system (glibc)

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

loaded via a namespace (and not attached):
[1] compiler_4.3.3 tools_4.3.3    renv_1.1.5

JohnADawson avatar Aug 01 '25 16:08 JohnADawson

Seems important to note that this is only an issue when options = list(create = TRUE) is specified?

cpsievert avatar Aug 01 '25 19:08 cpsievert

@cpsievert, that seems so.

JohnADawson avatar Aug 01 '25 19:08 JohnADawson

I think this is expected because the bookmark as far as I remember only restores the inputs. So, when the input widget's UI is initialized with the values the bookmark is able to choose them.

In this case the selectize Input dynamically changes the input choices which is out of the scope of the bookmark restore (as it is only meant to restore inputs, not choices).

The workaround I would recommend is to use onRestore to update the choices too:

library(shiny)

ui <- function(request) {
  shiny::fluidPage(
    shiny::selectizeInput(
      "my_selectize",
      "Selectize",
      character(0L),
      multiple = TRUE,
      options = list(create = TRUE)
    ),
    shiny::verbatimTextOutput("my_text"),
    shiny::bookmarkButton()
  )
}

server <- function(input, output, session) {
  output$my_text <- shiny::renderPrint(input$my_selectize)
  onRestore(function(state) {
    updateSelectizeInput(
      session,
      "my_selectize",
      selected = state$input$my_selectize,
      choices = state$input$my_selectize
    )
  })
}

shiny::shinyApp(ui, server, enableBookmarking = "url")

vedhav avatar Aug 02 '25 21:08 vedhav

@vedhav, thank you for your reply.

I think this is expected

I did not expect it, and it seems to me to be a bug: the selectizeInput, and everything downstream in the reactive graph of the application, ought to be the same after restoration.

JohnADawson avatar Aug 05 '25 08:08 JohnADawson

@vedhav, thank you for the work-around. However, if persist = FALSE the state of the selectizeInput differs after restoration.

ui <- function(request) {
  shiny::fluidPage(
    shiny::selectizeInput(
      "my_selectize",
      "Selectize",
      character(0L),
      multiple = TRUE,
      options = list(create = TRUE, persist = FALSE)
    ),
    shiny::verbatimTextOutput("my_text"),
    shiny::bookmarkButton()
  )
}

server <- function(input, output, session) {
  output$my_text <- shiny::renderPrint(input$my_selectize)
  shiny::onRestore(
    function(state) {
      shiny::updateSelectizeInput(
        session,
        "my_selectize",
        selected = state$input$my_selectize,
        choices = state$input$my_selectize
      )
    }
  )
}

shiny::shinyApp(ui, server, enableBookmarking = "url")

Run the application; enter "a,b,c," in the selectizeInput; click the bookmark button; copy the link.

Image

Now, in the original application if "c" is deleted it is not suggested.

Image

But in the restored application

Image

if "c" is deleted it is suggested.

Image

So the application is not restored exactly.

JohnADawson avatar Aug 05 '25 08:08 JohnADawson

If that is what you really want, you can achieve this by storing the choices state which can be referenced during the bookmark restore.

library(shiny)

ui <- function(request) {
  shiny::fluidPage(
    shiny::selectizeInput(
      "my_selectize",
      "Selectize",
      character(0L),
      multiple = TRUE,
      options = list(create = TRUE, persist = FALSE)
    ),
    shiny::verbatimTextOutput("my_text"),
    shiny::bookmarkButton()
  )
}

server <- function(input, output, session) {
  output$my_text <- shiny::renderPrint(input$my_selectize)
  my_selectize_choices <- reactiveVal()
  observeEvent(input$my_selectize, {
    my_selectize_choices(unique(c(input$my_selectize, my_selectize_choices())))
  })
  shiny::onBookmark(
    function(state) {
      state$values$my_selectize_choices <- my_selectize_choices()
    }
  )
  shiny::onRestore(
    function(state) {
      shiny::updateSelectizeInput(
        session,
        "my_selectize",
        selected = state$input$my_selectize,
        choices = state$values$my_selectize_choices
      )
    }
  )
}

shiny::shinyApp(ui, server, enableBookmarking = "url")

vedhav avatar Aug 05 '25 08:08 vedhav

@vedhav, thank you, but that does not work: the behaviour is the same as before. However, I have worked around the bug differently.

JohnADawson avatar Aug 05 '25 09:08 JohnADawson

I don't understand how you get the same behaviour as before. Isn't this what you expected? Can you elaborate on what you expected and what failed? It will be helpful for someone else trying to achieve the same thing.

https://github.com/user-attachments/assets/f414c554-f896-433e-aafa-06e6a2e48726

vedhav avatar Aug 05 '25 09:08 vedhav