David
David

Reputation: 10182

Leaflet in another tab not updated with leafletproxy before visiting tab

I am making an application using shiny that uses multiple tabs. On one tab (not the starting tab) I display a leaflet map, which is controlled by widgets on different tabs.

The issue is that if I change the inputs on one tab, without visiting the map first, and then visit the map, the map is not updated. However, changing the inputs after or while being on the map tab, the map is updated.

To replicate the issue:

  1. run the following code
  2. change the input color to blue (without visiting the map tab first!)
  3. go to the "Map" tab
    • expected behavior: blue dot. Actual behavior: no dot (not yet drawn, as if the observe() didn't get triggered (note that observe is triggered but has no effect), or the leaflet was not rendered)
  4. change the color to yellow
    • yellow dot appears
  5. go to the "Other" tab and change color to green
  6. go back to the "Map" tab and see a green dot

Similarly, when the app is started and we directly go to the map, I would expect a red dot to be displayed. Instead there is no dot.

Code:

library(shiny)
library(leaflet)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      selectInput("color", "Color", choices = c("red", "blue", "yellow", "green"))
    ),
    mainPanel(
      tabsetPanel(
        tabPanel("Other", h1("Empty Tab 1")),
        tabPanel("Map", leafletOutput("map"))
      )
    )
  )
)

server <- function(input, output, session) {
  # the base map and the circles are separated due to data restrictions
  # in the actual app!
  output$map <- renderLeaflet({
    leaflet() %>% 
      addTiles()
  })
  observe({
    leafletProxy("map") %>% 
      addCircles(lng = 0, lat = 0, radius = 3e6, color = input$color)
  })
}

shinyApp(ui, server)

I suspect that leafletProxy doesn't work as the leaflet widget is not yet rendered in step 2.

Any idea how to fix this issue?

In my real-life app, the first tab allows the user to upload data, while the second tab displays the data using leaflet, therefore the leaflet map gets updated and configured before its actually rendered...

Note that creating the leaflet in one go (Creating the map in the observe() without leafletProxy) is not an option due to various reason (size of leaflet, being dependent on other reactive values, scenarios etc.).

Upvotes: 4

Views: 986

Answers (1)

St&#233;phane Laurent
St&#233;phane Laurent

Reputation: 84529

This works with the output option suspendWhenHidden set to FALSE and by adding a dependency to the tabset in the observer:

library(shiny)
library(leaflet)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      selectInput("color", "Color", choices = c("red", "blue", "yellow", "green"))
    ),
    mainPanel(
      tabsetPanel(
        tabPanel("Other", h1("Empty Tab 1")),
        tabPanel("Map", leafletOutput("map")),
        id = "tabset"
      )
    )
  )
)

server <- function(input, output, session) {
  
  output$map <- renderLeaflet({
    leaflet() %>% 
      addTiles()
  })
  outputOptions(output, "map", suspendWhenHidden = FALSE)
  
  proxy <- leafletProxy("map")
  
  observeEvent(list(input$tabset, input$color), {
    proxy %>% 
      addCircles(lng = 0, lat = 0, radius = 3e6, color = input$color)
  })
}

shinyApp(ui, server)

Upvotes: 5

Related Questions