rshinymoduleshinyappsgolem

How do you have different server execution based on selected tabItem() in shiny?


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

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
)

Solution

  • 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")
        }
      )
    )