Search code examples
rshinyr-leaflet

How can I make a custom function be reactive?


I would like user input to control a leaflet map. I can get this to work if the leaflet code is written in full in the server function. But as the leaflet map (will be) complicated I want to move this into a separate function. When I do this the app works fine on startup, displaying the map for the selected location. However, changes to the input do not trigger the map to be updated. I've tried passing the input or a reactive into the map function but neither cause the map to be reactive. What do I need to do make it reactive? Thanks

library(shiny)
library(leaflet)


create_leaflet_map <- function(df) {
  renderLeaflet({
    leaflet() %>%
      addMarkers(df$lon, df$lat) %>%
      addTiles()
  })
}

#dummy data
places_data <- data.frame(name = c('Paris','London'),
                         lat = c(48.9,51.5),
                         lon = c(2.34,-0.12))

# Define UI
ui <- fluidPage(
  fluidRow(
    column(12,
           selectizeInput(inputId = 'place', label = "Pick place:", choices = c('Paris', 'London'))
           )
  ),
  fluidRow(
    column(12, 
           textOutput(outputId = 'place_name'),
           #MAP SECTION
           tags$div(
             leafletOutput("mymap", width = 345, height = 345)
           ),
    )
  )
)

# Define server logic
server <- function(input, output) {
  #get the reactive data based on picked place
  place_data <- reactive({subset(places_data, name == input$place)})  

  #OUTPUTS
  #print place name on screen
  output$place_name <- renderText(input$place)
  #make a leaflet map using the reactive place_data passed to the function
  output$mymap <- create_leaflet_map(df = place_data())

  #non-function version that works
  # output$mymap <- renderLeaflet({
  #   leaflet() %>%
  #     addMarkers(place_data()$lon, place_data()$lat) %>%
  #     addTiles()
  # })
}

# Run the application 
shinyApp(ui = ui, server = server)

Solution

  • Don't make the renderLeaflet part of your function. Instead just do

    create_leaflet_map <- function(df) {
        leaflet() %>%
          addMarkers(df$lon, df$lat) %>%
          addTiles()
    }
    

    and then in your server function do

    output$mymap <- renderLeaflet(create_leaflet_map(place_data()))
    

    Then everything will be reactive in the way you want.