dreamRs / datamods

Shiny modules to import and manipulate data into an application or addin
https://dreamrs.github.io/datamods/
GNU General Public License v3.0
138 stars 34 forks source link

Usage of `select_group_ui` in a Shiny module #63

Open shosaco opened 1 year ago

shosaco commented 1 year ago

Hi,

I cannot get select_group_ui() and select_group_server() get to work inside a shiny module.

I added ns() to the IDs but possibly the virtualSelectInput()s can't communicate properly due to wrong namespaces. I suggest this feature is not implemented, or am I missing something important?

The following minimal example is the standard example from the help page, with the difference that I change the code so that the select_group_ui() and -server() are used inside a module.

Any help would be appreciated.

library(shiny)
library(datamods)
library(shinyWidgets)

myModuleUI <- function(id){
  ns <- NS(id) 
  fluidRow(
    column(
      width = 10, offset = 1,
      tags$h3("Filter data with select group module"),
      shinyWidgets::panel(
        select_group_ui(
          id = ns("my-filters"),
          params = list(
            list(inputId = ns("Manufacturer"), label = "Manufacturer:"),
            list(inputId = ns("Type"), label = "Type:"),
            list(inputId = ns("AirBags"), label = "AirBags:"),
            list(inputId = ns("DriveTrain"), label = "DriveTrain:")
          )
        ),
        status = "primary"
      ),
      reactable::reactableOutput(outputId = ns("table"))
    )
  )
}
myModuleServer <- function(id){
  moduleServer(id, function(input, output, session){
    res_mod <- select_group_server(
      id = session$ns("my-filters"),
      data = reactive(MASS::Cars93),
      vars = reactive(c("Manufacturer", "Type", "AirBags", "DriveTrain"))
    )
    output$table <- reactable::renderReactable({
      reactable::reactable(res_mod())
    })
  })

}

ui <- fluidPage(
  # theme = bslib::bs_theme(version = 5L),
  myModuleUI("id")
)

server <- function(input, output, session) {
  myModuleServer("id")
}
shinyApp(ui, server)
feddelegrand7 commented 1 year ago

The following will work:

library(shiny)
library(datamods)
library(shinyWidgets)

myModuleUI <- function(id){
  ns <- NS(id) 
  fluidRow(
    column(
      width = 10, offset = 1,
      tags$h3("Filter data with select group module"),
      shinyWidgets::panel(
        select_group_ui(
          id = ns("my-filters"),
          params = list(
            Manufacturer = list(inputId = "Manufacturer", label = "Manufacturer:"),
            Type = list(inputId = "Type", label = "Type:"),
            AirBags = list(inputId = "AirBags", label = "AirBags:"),
            DriveTrain = list(inputId = "DriveTrain", label = "DriveTrain:")
          )
        ),
        status = "primary"
      ),
      reactable::reactableOutput(outputId = ns("table"))
    )
  )
}
myModuleServer <- function(id){
  moduleServer(id, function(input, output, session){
    res_mod <- select_group_server(
      id = "my-filters",
      data_r  = reactive(MASS::Cars93),
      vars_r  = reactive(c("Manufacturer", "Type", "AirBags", "DriveTrain"))
    )
    output$table <- reactable::renderReactable({
      reactable::reactable(res_mod())
    })
  })

}

ui <- fluidPage(
  # theme = bslib::bs_theme(version = 5L),
  myModuleUI("change")
)

server <- function(input, output, session) {
  myModuleServer("change")
}
shinyApp(ui, server)

@pvictor maybe it's a good idea to display the following example in the docs, in case one wants to apply the Select Group Module in the context of a Shiny Module?

shosaco commented 1 year ago

The following will work:

Thanks! So the following points are important:

library(shiny)
library(datamods)
library(shinyWidgets)

myModuleUI <- function(id){
  ns <- NS(id) 
  tagList(shinyWidgets::panel(
    select_group_ui(
      id = ns("my-filters"),
      params = list(
        # inputIds must be column names of the data, without ns() function!
        list(inputId = "Manufacturer", label = "Manufacturer:"),
        list(inputId = "Type", label = "Type:")
      )      
    ),
    reactable::reactableOutput(outputId = ns("table")))
  )

}
myModuleServer <- function(id){
  moduleServer(id, function(input, output, session){
    res_mod <- select_group_server(
      id = "my-filters",
      data_r  = MASS::Cars93,
      vars_r  = c("Manufacturer", "Type")
    )
    output$table <- reactable::renderReactable({
      reactable::reactable(res_mod())
    })
  })

}

ui <- fluidPage(
  myModuleUI("id")
)

server <- function(input, output, session) {
  myModuleServer("id")
}
shinyApp(ui, server)
pvictor commented 1 year ago

Thank you both if you have ideas to improve the interface, I'm interested. In the meantime I will add the example for use in a shiny module.

Victor