Search code examples
rshinymapboxshiny-reactivityshinymodules

Button passed to nested module doesn't work properly


For some reason I need to nest modules. I passed button to nested module mod_coordinates_server but when I click the button points do not show up on the map. I used here reactive and button is passed correctly - when you uncomment print(btn()) (in observeEvent) you'll see that values are returned to console properly. It means that button works corectly. So why it doesn't work for points? Is it something wrong with namespace?

Below working example:

library(shiny)
library(mapboxer)
library(dplyr)
library(sf)


moduleServer <- function(id, module) {
    callModule(module, id)
}

# UI #
mod_btn_UI <- function(id) {
    
    ns <- NS(id)
    tagList(
        actionButton(ns("btn"), "Click me!"),
        mod_coordinates_UI(ns("proxyMap"))
    )
}

# Server #
mod_btn_server <- function(id){
    moduleServer(id, function(input, output, session) {

        btn <- reactive({input$btn})
        mod_coordinates_server("proxyMap", btn)
        
    })
}


# Module Coordinates

mod_coordinates_UI <- function(id) {
    
    ns <- NS(id)
    tagList(
        mapboxerOutput(ns("map"))
    )
}


mod_coordinates_server <- function(id, btn){
    moduleServer(id, function(input, output, session) {
        
        ns <- NS(id)
        
        coords <- quakes %>%
            sf::st_as_sf(coords = c("long","lat"), crs = 4326)
        
        output$map <- mapboxer::renderMapboxer({
            mapboxer::mapboxer(
                style = mapboxer::basemaps$Mapbox$light_v10,
                center = c(174.387636,-33.543557),
                pitch = 5,
                padding = 0,
                zoom = 3)
        })
        
        observeEvent(btn(), {
            # print(btn())
            mapboxer::mapboxer_proxy(ns("map")) %>%
                mapboxer::add_circle_layer(
                    id = "xyz",
                    source = mapboxer::as_mapbox_source(coords),
                    circle_color = "#952444",
                    circle_opacity = 0.7,
                    circle_radius = 6
                ) %>%
                mapboxer::update_mapboxer()
        })        
       
    })
 }


# FINAL App #

ui <- fluidPage(
    
    tagList(
        mod_btn_UI("test-btn"))
)

server <- function(input, output, session) {
    
    mod_btn_server("test-btn")
    
}

shinyApp(ui = ui, server = server)

Solution

  • Call the second module also in the main app. Try this

    moduleServer <- function(id, module) {
      callModule(module, id)
    }
    
    # UI #
    mod_btn_UI <- function(id) {
      
      ns <- NS(id)
      tagList(
        actionButton(ns("btn"), "Click me!")
        
      )
    }
    
    # Server #
    mod_btn_server <- function(id){
      moduleServer(id, function(input, output, session) {
        
        reactive({input$btn})
        # mod_coordinates_server("proxyMap", btn)
        
      })
    }
    
    # Module Coordinates
    
    mod_coordinates_UI <- function(id) {
      
      ns <- NS(id)
      tagList(
        mapboxerOutput(ns("map"))
      )
    }
    
    mod_coordinates_server <- function(id, btn){
      moduleServer(id, function(input, output, session) {
        
        ns <- session$ns
        
        coords <- quakes %>%
          sf::st_as_sf(coords = c("long","lat"), crs = 4326)
        
        output$map <- mapboxer::renderMapboxer({
          mapboxer::mapboxer(
            style = mapboxer::basemaps$Mapbox$light_v10,
            center = c(174.387636,-33.543557),
            pitch = 5,
            padding = 0,
            zoom = 3)
        })
        
        observeEvent(btn(), {
          print(btn())
          mapboxer::mapboxer_proxy(ns("map")) %>%
            mapboxer::add_circle_layer(
              id = "xyz",
              source = mapboxer::as_mapbox_source(coords),
              circle_color = "#952444",
              circle_opacity = 0.7,
              circle_radius = 6
            ) %>%
            mapboxer::update_mapboxer()
        })        
        
      })
    }
    
    
    # FINAL App #
    
    ui <- fluidPage(
      
      tagList(
        mod_btn_UI("test-btn"), 
        mod_coordinates_UI("proxyMap")
        )
    )
    
    server <- function(input, output, session) {
      
      btn <- mod_btn_server("test-btn")
      mod_coordinates_server("proxyMap", btn)
    }
    
    shinyApp(ui = ui, server = server)
    

    If you wish to maintain nesting, try this

    library(shiny)
    library(mapboxer)
    library(dplyr)
    library(sf)
    
    Sys.setenv(MAPBOX_API_TOKEN = "pk.eyJ1IjoiaHdsIiwiYSI6ImNramJxY2YxcDV2YXoyeW40YXlvbmUyazQifQ.7HBEvMyrAnVpkKO7MNH7ww")
    
    moduleServer <- function(id, module) {
      callModule(module, id)
    }
    
    # UI #
    mod_btn_UI <- function(id) {
      
      ns <- NS(id)
      tagList(
        actionButton(ns("btn"), "Click me!"),
        mod_coordinates_UI(ns("proxyMap"))
      )
    }
    
    # Server #
    mod_btn_server <- function(id){
      moduleServer(id, function(input, output, session) {
        
        # btn <- reactive({input$btn})
        mod_coordinates_server("proxyMap", reactive({input$btn}))
        
      })
    }
    
    
    # Module Coordinates
    
    mod_coordinates_UI <- function(id) {
      
      ns <- NS(id)
      tagList(
        mapboxerOutput(ns("map"))
      )
    }
    
    
    mod_coordinates_server <- function(id, btn){
      moduleServer(id, function(input, output, session) {
        
        ns <- session$ns
        
        coords <- quakes %>%
          sf::st_as_sf(coords = c("long","lat"), crs = 4326)
        
        output$map <- mapboxer::renderMapboxer({
          mapboxer::mapboxer(
            style = mapboxer::basemaps$Mapbox$light_v10,
            center = c(174.387636,-33.543557),
            pitch = 5,
            padding = 0,
            zoom = 3)
        })
        
        observeEvent(btn(), {
          # print(btn())
          mapboxer::mapboxer_proxy(ns("map")) %>%
            mapboxer::add_circle_layer(
              id = "xyz",
              source = mapboxer::as_mapbox_source(coords),
              circle_color = "#952444",
              circle_opacity = 0.7,
              circle_radius = 6
            ) %>%
            mapboxer::update_mapboxer()
        })        
        
      })
    }
    
    
    # FINAL App #
    
    ui <- fluidPage(
      
      tagList(
        mod_btn_UI("test-btn"))
    )
    
    server <- function(input, output, session) {
      
      mod_btn_server("test-btn")
      
    }
    
    shinyApp(ui = ui, server = server)
    

    output