Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bookmarking and restoring dynamically added tabs

I have a shiny app that dynamically add tabs to a tabset panel. When trying to use boookmarking in order to save the state and then restore it, I find that only the last added tab is being bookmarked.

I have tried using both bookmarking to the server as well as to URL. In both cases only the initial tabs (not added dynamically) plus the last dynamically added tab was bookmarked. All other dynamicalled added tabs were not bookmarked and thus did not appear when I restored the state.

Here is a reproducible code:

library(shiny)
# example app for bookmarking and restoring dynamically added tabs
# only the last added tab is bookmarked. 

ui <- function(request) {
  fluidPage(
  sidebarLayout(
    sidebarPanel(
      actionButton("add", "Add 'Dynamic' tab"),
      actionButton("remove", "Remove selected tab"), 
      # Add a bookmarking buttons
      bookmarkButton(),
      actionButton("restore", "Restore State")

    ),
    mainPanel(
      tabsetPanel(id = "tabs",
                  tabPanel("Hello", "This is the hello tab")
      )
    )
  )
)
}
               
server <- function(input, output, session) {
  observeEvent(input$add, {
    insertTab(inputId = "tabs",
              tabPanel(paste("Dynamic",input$add), "This a dynamically-added tab")
    )
  })
  
  observeEvent(input$remove, {
    removeTab(inputId = "tabs", target = input$tabs)
  })
  
  onBookmarked(function(url) {
    updateQueryString(url)
  })
  
  observeEvent(input$restore, {
    session$reload() 
  }) 
}

enableBookmarking(store = "url")
shinyApp(ui, server)
like image 597
amir61 Avatar asked Dec 11 '25 11:12

amir61


1 Answers

Well, this behaviour is by design. You see that your bookmark url contains the value of input$add:

Screenshot of the URL of the Shiny app showing the address line which reads as http://127.0.0.1:5398/?inputs&tabs=%22Hello%22&remove=0&add=3&restore=0

That is the value of input$add (3 in this case) is stored. Upon restore you set input$add to three, this fires your observer, which adds one dynamic panel (labeled Dynamic 3).

You need to store all added tabs and supply a "smarter" bookmark (restore) routine like this:

library(shiny)
library(tibble)
library(dplyr)
library(purrr)

ui <- function(request) {
   fluidPage(
      sidebarLayout(
         sidebarPanel(
            actionButton("add", "Add 'Dynamic' tab"),
            actionButton("remove", "Remove selected tab"), 
            # Add a bookmarking buttons
            bookmarkButton(),
            actionButton("restore", "Restore State")
         ),
         mainPanel(
            tabsetPanel(id = "tabs",
                        tabPanel("Hello", "This is the hello tab")
            )
         )
      )
   )
}

server <- function(input, output, session) {
   dyn_tabs <- reactiveVal(NULL)
   added_tabs <- reactiveVal(NULL)
   cnt <- reactiveVal(0L)
   
   observeEvent(input$add, {
      cnt(cnt() + 1)
      id <- paste("Dynamic", cnt())
      dyn_tabs(c(dyn_tabs(), id))
   })
   
   observeEvent(input$remove, {
      remove_me <- input$tabs
      dyn_tabs(setdiff(dyn_tabs(), remove_me))
      added_tabs(setdiff(added_tabs(), remove_me))
      removeTab(inputId = "tabs", target = remove_me)
   })
   
   observeEvent(dyn_tabs(), {
      new_tabs <- setdiff(dyn_tabs(), added_tabs())
      walk(new_tabs, ~ insertTab(inputId = "tabs", 
                                 tabPanel(.x, "This is a dynamically added tab")))
      added_tabs(union(added_tabs(), new_tabs))
   })
   
   setBookmarkExclude(c("add", "delete"))
   
   onBookmark(function(state) {
      state$values$dyn_tabs <- dyn_tabs()
      state$values$cnt <- cnt()
   })
   
   onBookmarked(function(url) {
      updateQueryString(url)
   })
   
   onRestored(function(state) {
      dyn_tabs(state$values$dyn_tabs)
      cnt(state$values$cnt)
   })
   
   observeEvent(input$restore, {
      session$reload()
   })
}

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

So basically we keep track about dynamic (but yet not added) panels (dyn_tabs) and save this vector upon bookmark. We keep also a list of added panels (added_tabs) in order not to re-render all panels upon change.

When we restore, we refill these vectors accordingly. We exclude input$add and input$remove from the bookmarking to avoid that it adds (removes) its element upon restore.

However, we keep track about the number of previous clicks (cnt) in order to get a proper labeling.

like image 69
thothal Avatar answered Dec 13 '25 15:12

thothal



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!