JohnCoene / cicerone

🏛️ Give tours of your Shiny apps
https://cicerone.john-coene.com
Other
187 stars 7 forks source link

Shiny app with hierarchical tabs and modules #64

Open jzadra opened 4 months ago

jzadra commented 4 months ago

I've looked at the documentation for how to use Cicerone with modules, and how to use it with tabs. However in my case of combining the two for a more complex app with nested tabs and nested modules, I've been unable to create a guide that tours through multiple tabs.

I think the main issue is that I'm unclear on how to determine the values for the tab and tab_id argument given the modules and tabs within tabs. But perhaps it is my element values too.

Here is a simplified example app:

library(shiny)
library(tidyverse)
library(cicerone)

# Module for subtabs ------------------------------------------------------

mod_subtabs_ui <- function(id){
  ns <- NS(id)
  tagList(
    tabsetPanel(
      id = ns("subTabs"),
      tabPanel("Chart", mod_chart_ui(ns("chart_1"))),
      tabPanel("Table", mod_table_ui(ns("table_1")))
    )
  )
}

#' subtabs Server Functions
#'
#' @noRd
mod_subtabs_server <- function(id){
  moduleServer( id, function(input, output, session){
    ns <- session$ns

    mod_chart_server("chart_1")
    mod_table_server("table_1")
  })
}

# Module for chart --------------------------------------------------------

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

  tagList(
      plotOutput(ns("chart"))
  )
}

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

    output$chart <- renderPlot(ggplot(mtcars, aes(x = mpg, y = cyl)) + geom_point())

  })
}

# Module for table --------------------------------------------------------

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

  tagList(
    sidebarLayout(
      sidebarPanel(
        mod_filter_ui(ns("filter_chart"))),
      mainPanel(
        tableOutput(ns("table"))
      )
    )
  )
}

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

    filt_mtcars <- isolate(mod_filter_server("filter_chart"))

    output$table <- renderTable(filt_mtcars())

  })
}

# Module for filter -------------------------------------------------------

mod_filter_ui <- function(id) {
  ns <- NS(id)
  tagList(
      selectInput(ns("cyl_filt"),
                  label = "Filter for # of Cylinders",
                  choices = NULL)
    )
}

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

    updateSelectInput("cyl_filt",
                      session = session,
                      choices = unique(mtcars$cyl),
                      selected = unique(mtcars$cyl)[1])

    filt_mtcars <- reactive(mtcars |> filter(cyl == input$cyl_filt))

    return(filt_mtcars)

  })
}

# Cicerone ----------------------------------------------------------------

guide <- Cicerone$
  new()$
  step(el = "mainTabs",
       "Main Tabs",
       "These are the main tabs set in the main server")$
  step(el = "tab1-subTabs",
       "Sub Tabs",
       "These are the subtabs under Tab1")$
  step(el = "tab1-chart_1-chart",
       "Chart",
       "This is a chart!")$
  step(el = "tab1-table_1-table", #This step does not work
       "Table",
       "This is a table!",
       tab = "table_1",
       tab_id = "tab1-table_1")$
  step(el = "tab1-table_1-table-cyl_filt", #This step does not work
       "Filters",
       "Here you can filter the table by number of cylinders.")

# Main app ----------------------------------------------------------------

ui <- fluidPage(
  use_cicerone(),
  mainPanel(
    tabsetPanel(id = "mainTabs",
      tabPanel("tab1", mod_subtabs_ui("tab1")),
      tabPanel("tab2", mod_subtabs_ui("tab2"))
    )
  )
)

server <- function(input, output, session) {

  guide$init()$start()

  mod_subtabs_server("tab1")
  mod_subtabs_server("tab2")

}

shinyApp(ui = ui, server = server)
jzadra commented 4 months ago

This may be due to the tab functionality of cicerone not working at all, or at least the example of how to do it not being correct, as I just realized that the example code provided for moving between tabs does not work itself.

jzadra commented 4 months ago

The example does not work with the CRAN version (1.0.4) but does work with the dev version (1.0.5.9000). However, the the example app code I shared still does not work. So the possibility that it was due to the general functionality not working has been ruled out, leaving the issue unsolved.