Search code examples
rshinyshinydashboardrshiny

Shiny bookmark cannot restore the selectizeinput


I have designed a simple shiny app (https://yuchenw.shinyapps.io/selectizeinput_bookmark/) with two selectizeInputs. The second selectizeInput's choices is based on the selection of the first one. For example, if I select "B" in "Select a letter", the available choices for "Select a number" becomes "B-1", "B-2", and "B-3".

This works well. But when I added a bookmark button, I cannot restore the second selectizeInput, only the first. For example, if I select "B" and "B-3" as follows, and then click the "Bookmark" button, I got an URL (https://yuchenw.shinyapps.io/selectizeinput_bookmark/?_inputs_&sidebarCollapsed=false&Example=%22Page%22&sidebarItemExpanded=null&_values_&Number_Select=%22B-3%22&Letter_Select=%22B%22).

enter image description here

When I copy and paste the URL to a web browser, the first one is "B" as expected, but the second one is "B-1".

enter image description here

I think it is related to the setting of my updateSelectizeInput, but I don't know how to fix it. Below is the complete code.

library(shiny)
library(shinydashboard)

dat <- data.frame(
  Letter = rep(c("A", "B", "C"), each = 3),
  Number = paste(rep(c("A", "B", "C"), each = 3),
                 rep(1:3, times = 3),
                 sep = "-")
)

ui <- function(request){
  dashboardPage(
    header = dashboardHeader(title = ""),
    sidebar = dashboardSidebar(
      sidebarMenu(
        id = "Example",
        menuItem(
          text = "Page",
          tabName = "Page"
          )),
      bookmarkButton()),
    body = dashboardBody(
      tabItems(
        tabItem(
        tabName = "Page",
        h2("SelectizeInput Bookmark Example"),
        fluidRow(
          box(
            title = "", status = "primary", solidHeader = TRUE, width = 6, collapsible = TRUE,
            selectizeInput(inputId = "Letter_Select", 
                           label = "Select a letter",
                           choices = c("A", "B", "C"),
                           options = list(
                             placeholder = 'Please select a letter below',
                             onInitialize = I('function() { this.setValue(""); }'),
                             create = TRUE)
            ),
            selectizeInput(inputId = "Number_Select", 
                           label = "Select a number",
                           choices = paste(rep(c("A", "B", "C"), each = 3),
                                           rep(1:3, times = 3),
                                           sep = "-"),
                           options = list(
                             placeholder = 'Please select a number below',
                             onInitialize = I('function() { this.setValue(""); }'),
                             create = TRUE)
            )
          )
        )
        )
      )
    )
  )
}

server <- function(input, output, session){
  
  observeEvent(c(input$Letter_Select), {
    updateSelectizeInput(session, inputId = "Number_Select", 
                         label = "Select a number",
                         choices = dat$Number[dat$Letter %in% input$Letter_Select],
                         server = TRUE)
  },
  ignoreInit = TRUE)
  
  # List of selectizeinput
  selectize_inputs <- c("Letter_Select", "Number_Select")
  
  setBookmarkExclude(names = selectize_inputs)
  
  onBookmark(function(state){
    for (selectize_input in selectize_inputs){
      state$values[[selectize_input]] <- isolate({input[[selectize_input]]})
    }
  })
  
  onRestore(function(state){
    updateSelectizeInput(session, inputId = "Letter_Select", 
                         choices = c("A", "B", "C"),
                         selected = state$values[["Letter_Select"]],
                         server = TRUE)
    updateSelectizeInput(session, inputId = "Number_Select", 
                         choices = dat$Number[dat$Letter %in% state$values[["Letter_Select"]]],
                         selected = state$values[["Number_Select"]],
                         server = TRUE)
    
  })
}

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

Notice that I have to use server = TRUE for selectizeInput as my real-world application has many choices I need to show. I also need to use shinydashboard and enableBookmarking = "url. Please let me know what you think.


Solution

  • This is due to observeEvent(c(input$Letter_Select),...) which is triggered after completion of onRestore and which resets changes made to Number_select.

    You could use a reactiveVal to avoid this reset after restoring the state:

    server <- function(input, output, session){
      
      restoreState <- reactiveVal(F)
      
      observeEvent(c(input$Letter_Select), {
        if (!restoreState()){    
          updateSelectizeInput(session, inputId = "Number_Select", 
                             label = "Select a number",
                             choices = dat$Number[dat$Letter %in% input$Letter_Select],
                             server = TRUE)
        }
        restoreState(F)
      },
      ignoreInit = TRUE)
      
      # List of selectizeinput
      selectize_inputs <- c("Letter_Select", "Number_Select")
      
      setBookmarkExclude(names = selectize_inputs)
      
      onBookmark(function(state){
        for (selectize_input in selectize_inputs){
          state$values[[selectize_input]] <- isolate({input[[selectize_input]]})
        }
      })
      
      onRestore(function(state){
        updateSelectizeInput(session, inputId = "Letter_Select", 
                             choices = c("A", "B", "C"),
                             selected = state$values[["Letter_Select"]],
                             server = TRUE)
    
        updateSelectizeInput(session, inputId = "Number_Select", 
                             choices = dat$Number[dat$Letter %in% state$values[["Letter_Select"]]],
                             selected = state$values[["Number_Select"]],
                             server = TRUE)
        restoreState(T)
      })
    }
    
    shinyApp(ui, server, enableBookmarking = "url")