leafletProxy stops working after renderUI changes leaflet dimensions

Created on 1 Aug 2017  路  4Comments  路  Source: rstudio/leaflet

I'm having some funny behavior with leafletProxy and renderUI. I want to be able to resize the leaflet map by user input, however after resizing, leafletProxy doesn't do anything and sometimes I get this message in the browser console:

Couldn't find map with id map1

See below for a slightly modified leafletProxy example reprex that includes this resizing ability. You can click on a marker to remove it, until you resize the map using the slider, then leafletProxy no longer does anything.

library(shiny)
library(leaflet)

ui <- fluidPage(
  sliderInput("mapWidth", "Map Width", 2.5, 97.5, 50),
  uiOutput("rootUI")
)
server <- function(input, output, session) {
  output$rootUI <- renderUI({
    req(input$mapWidth)
    leafletOutput("map1", width = paste0(input$mapWidth, "%"))
  })
  output$map1 <- renderLeaflet({
    leaflet() %>%
      addCircleMarkers(lng = runif(10),
                       lat = runif(10),
                       layerId = paste0("marker", 1:10))
  })
  observeEvent(input$map1_marker_click, {
    leafletProxy("map1", session) %>%
      removeMarker(input$map1_marker_click$id)
  })
}
shinyApp(ui = ui, server = server)

I've seen similar questions asked with shinydashboard and that console warning, Couldn't find map with id map1, however I wasn't able to solve this issue by using the suggested outputOptions(output, "map1", suspendWhenHidden = FALSE).

I am using the latest development versions of shiny and leaflet.

Please let me know if I am trying to do something bad in shiny, and whether this should be done with JavaScript instead?

Thanks so much for the awesome package!
Hayden

Most helpful comment

@Felixjalvarez

There are a couple of issues with the original setup.

  • leafletOutput should only be used when making the ui. Ex: ui <- fluidPage(leafletOutput('myMap'))
  • The bullet above makes changing the width of the output require a non-standard approach.

An example app using something similar to the js code above.

library(shiny)
library(leaflet)

ui <- fluidPage(

  sliderInput("mapWidth", "Map Width", 2.5, 97.5, 50),
  leafletOutput("map1"),
  uiOutput("map1js") # adjust width dynamically
)
server <- function(input, output, session) {
  # update the map width dynamically
  output$map1js <- renderUI({
    tags$script(HTML(paste0(
      'document.getElementById("map1").style.width="', input$mapWidth, '%";'
    )))
  })
  output$map1 <- renderLeaflet({
    leaflet() %>%
      addCircleMarkers(lng = runif(10),
                       lat = runif(10),
                       layerId = paste0("marker", 1:10))
  })
  observeEvent(input$map1_marker_click, {
    leafletProxy("map1", session) %>%
      removeMarker(input$map1_marker_click$id)
  })
}

shinyApp(ui = ui, server = server)

All 4 comments

Please feel free to close this issue if it doesn't make sense. I've made a quick fix with the following instead of re-rendering in the server function:

$(document).on('shiny:inputchanged', evt => { if (evt.name === "mapWidth") { document.getElementById("map1").style.width =evt.value + "%"; } });

I need more details on how to implement this solution ?

@Felixjalvarez

There are a couple of issues with the original setup.

  • leafletOutput should only be used when making the ui. Ex: ui <- fluidPage(leafletOutput('myMap'))
  • The bullet above makes changing the width of the output require a non-standard approach.

An example app using something similar to the js code above.

library(shiny)
library(leaflet)

ui <- fluidPage(

  sliderInput("mapWidth", "Map Width", 2.5, 97.5, 50),
  leafletOutput("map1"),
  uiOutput("map1js") # adjust width dynamically
)
server <- function(input, output, session) {
  # update the map width dynamically
  output$map1js <- renderUI({
    tags$script(HTML(paste0(
      'document.getElementById("map1").style.width="', input$mapWidth, '%";'
    )))
  })
  output$map1 <- renderLeaflet({
    leaflet() %>%
      addCircleMarkers(lng = runif(10),
                       lat = runif(10),
                       layerId = paste0("marker", 1:10))
  })
  observeEvent(input$map1_marker_click, {
    leafletProxy("map1", session) %>%
      removeMarker(input$map1_marker_click$id)
  })
}

shinyApp(ui = ui, server = server)

excellent solution, thank you very much for the help!

Was this page helpful?
0 / 5 - 0 ratings