0

Background I am using {brochure} and {golem} to build a shiny app. I have one outer module grid that consists of inner modules subGrid2 which displays the same module UI on two tabs.

GOAL

  • have a module subGrid2 that can be used for repeating graph visualizations on multiple tabs.
  • in the REPREX --> fake graph generated from {shinipsum} to be displayed on the "Home" tab + "Portfolio" tab
  • use observeEvent to look at the slected tab and generate server response respectivley

Problem

The observeEvent reactive expr. fails to recognize when the corresponding tab is selected to generate the correct server response.

-using the reprex below replicates my issue-

TL/DR

  1. Why wont the observeEvent reactive generate the correct server response per the selected tab?

REPREX

uncomment observeEvent to see error

#22.2.22
library(brochure)

library(shiny)

library(shinipsum)

library(shinydashboard)

library(shinydashboardPlus)

mod_subGrid2_ui <- function(id) {
    ns <- NS(id)
    tagList(
        plotOutput(ns("plot"))
    )
}

mod_subGrid2_server <- function(id) {
    moduleServer(id, function(input, output, session) {
        ns <- session$ns

        output$plot <- renderPlot({
            shinipsum::random_ggplot()
        })
    })
}

#Setup dashboard

mod_Grid_ui <- function(id) {
    ns <- NS(id)

    shinydashboardPlus::dashboardPage(
        skin = "midnight",
        header = dashboardHeader(title = "test"),
        sidebar = dashboardSidebar(
            shinydashboard::sidebarMenu(
                # Setting id makes input$tabs give the tabName of currently-selected tab
                id = "tabs",
                menuItem("Home", tabName = "home", icon = icon("tachometer-alt")),
                menuItem("Portfolio", tabName = "portfolio", icon = icon("chart-line"), badgeLabel = "new",
                         badgeColor = "green")
            )
        ),

        body = shinydashboard::dashboardBody(
            # Enable shinyjs
            shinyjs::useShinyjs(),

            shinydashboard::tabItems(
                shinydashboard::tabItem("home",
                                        shiny::tagList(
                                            div(p("Content for 1st tab goes here -- GRID MODULE")),
                                            mod_subGrid2_ui(ns("subGrid2_ui_1"))
                                        )
                ),
                shinydashboard::tabItem("portfolio",
                                        shiny::tagList(
                                            div(p("Content for 2nd goes here -- GRID MODULE (2x)")),
                                            titlePanel(title = "The same module UI goes here"),

mod_subGrid2_ui(ns("subGrid2_ui_2"))
                                        )
                )
            )
        )
    )
}

mod_Grid_server <- function(id) {
    moduleServer(id, function(input, output, session) {
        ns <- session$ns
        mod_subGrid2_server("subGrid2_ui_1")
        mod_subGrid2_server("subGrid2_ui_2")

       ## uncomment to try
        # observeEvent(input$tabs,{
        #   if(input$tabs == "home"){
        #     # <subGrid> server fragment
        #     mod_subGrid2_server("subGrid2_ui_1")
        #   } else if(input$tabs == "portfolio"){
        #     mod_subGrid2_server("subGrid2_ui_1")
        #   }
        # }, ignoreNULL = TRUE, ignoreInit = TRUE)
    })
}

brochureApp(
    page(
        href = "/",
        ui = tagList(
            mod_Grid_ui("grid_1")
        ),
        server = function(input, output, session) {
            mod_Grid_server("grid_1")
        }
    ),
    wrapped = shiny::tagList
)
JJ Fantini
  • 213
  • 1
  • 11

1 Answers1

2

When using a module nested inside another module, you need to ns() the id of the nested UI function. So here, mod_subGrid2_ui(ns("subGrid2_ui_1")).

Here is a minimal reprex:

mod_subGrid2_ui <- function(id) {
  ns <- NS(id)
  tagList(
    plotOutput(ns("plot"))
  )
}

mod_subGrid2_server <- function(id) {
  moduleServer(id, function(input, output, session) {
    ns <- session$ns

    output$plot <- renderPlot({
      shinipsum::random_ggplot()
    })
  })
}

mod_Grid_ui <- function(id) {
  ns <- NS(id)
  tagList(
    mod_subGrid2_ui(ns("subGrid2_ui_1"))
  )
}

mod_Grid_server <- function(id) {
  moduleServer(id, function(input, output, session) {
    ns <- session$ns
    mod_subGrid2_server("subGrid2_ui_1")
  })
}

brochureApp(
  page(
    href = "/",
    ui = tagList(
      mod_Grid_ui("grid_1")
    ),
    server = function(input, output, session) {
      mod_Grid_server("grid_1")
    }
  )
)
Colin FAY
  • 4,849
  • 1
  • 12
  • 29
  • 1
    Sorry, the reprex throws an error and can't be launched on my laptop, so I'm trying to guess, as there are a lot of code :) You need to ns() the modules that are inside other module, so mod_subGrid2_server(ns("subGrid2_ui_1")). See my updated answer. – Colin FAY Feb 23 '22 at 07:54
  • That seem to have solved the issue for me! Am I correct in assuming that the server module does not need to be ns() as namespacing is implicit? https://mastering-shiny.org/scaling-modules.html#namespacing – JJ Fantini Feb 23 '22 at 10:58
  • There is also no more use for ` ui = function(request) { mod_dashboard_ui(id = id) }`? as that logic is implied with the module correct? – JJ Fantini Feb 23 '22 at 11:48
  • 1
    @JJFantini there is no need to namespace the server id indeed, it's done under the hood by shiny. For the ui = function(request){}, it depends on wether you want to ui to be rendered __at application runtime__ (i.e the function is run every time a user connect) or __at application launch__ (i.e when you call brochureApp() in your R session). – Colin FAY Feb 23 '22 at 13:51
  • I have updated question to better reflect the problem. – JJ Fantini Feb 23 '22 at 14:08