DocProc
DocProc

Reputation: 103

No output from Reactive Module using selectizeGroup

I'd like to have one pickerinput limit the options in the Selectize Group module of ShinyWisgets. I can get that to work using a reactive expression. However, nothing is produced in the table for me to view the results. What am I missing?

I suspect I made an error in the mpg_filter expression.

# https://dreamrs.github.io/shinyWidgets/reference/selectizeGroup-module.html

library(shiny)
library(shinyWidgets)

data("mpg", package = "ggplot2")

ui <- fluidPage(
  fluidRow(
    column(
      width = 10, offset = 1,
      tags$h3("Filter data with selectize group"),
      panel(
        pickerInput(
          inputId = "car_select",
          choices = unique(mpg$manufacturer),
          options = list(
            `live-search` = TRUE,
            title = "None selected"
          ),
        ),


        selectizeGroupUI(
          id = "my-filters",
          params = list(
            manufacturer = list(inputId = "manufacturer", title = "Manufacturer:"),
            model = list(inputId = "model", title = "Model:"),
            trans = list(inputId = "trans", title = "Trans:"),
            class = list(inputId = "class", title = "Class:")
          )
        ),
        status = "primary"
      ),
      dataTableOutput(outputId = "table")
    )
  )
)

server <- function(input, output, session) {
  mpg_filter <- reactive({
    mpg %>%
      filter(mpg$manufacturer %in% input$car_select)
  })


  res_mod <- reactive({
    callModule(
      module = selectizeGroupServer,
      id = "my-filters",
      data = mpg_filter(),
      vars = c("manufacturer", "model", "trans", "class")
    )
  })

  output$table <- renderDataTable(res_mod())
}

shinyApp(ui, server)

Upvotes: 3

Views: 502

Answers (1)

Aur&#232;le
Aur&#232;le

Reputation: 12839

Since v0.5.0 (November 2019),

selectizeGroupServer() (module selectizeGroup) now accept reactive data and reactive vars arguments, see examples for details ?selectizeGroupServer.

The last example in ?selectizeGroupServer is effectively a direct answer to this question:

# Subset data -------------------------------------------------------------

library(shiny)
library(shinyWidgets)

data("mpg", package = "ggplot2")

ui <- fluidPage(
  fluidRow(
    column(
      width = 10, offset = 1,
      tags$h3("Filter data with selectize group"),
      panel(
        pickerInput(
          inputId = "car_select",
          choices = unique(mpg$manufacturer),
          options = list(
            `live-search` = TRUE,
            title = "None selected"
          )
        ),
        selectizeGroupUI(
          id = "my-filters",
          params = list(
            manufacturer = list(inputId = "manufacturer", title = "Manufacturer:"),
            model = list(inputId = "model", title = "Model:"),
            trans = list(inputId = "trans", title = "Trans:"),
            class = list(inputId = "class", title = "Class:")
          )
        ),
        status = "primary"
      ),
      DT::dataTableOutput(outputId = "table")
    )
  )
)

server <- function(input, output, session) {
  
  mpg_filter <- reactive({
    subset(mpg, manufacturer %in% input$car_select)
  })
  
  res_mod <- callModule(
    module = selectizeGroupServer,
    id = "my-filters",
    data = mpg_filter,
    vars = c("manufacturer", "model", "trans", "class")
  )
  
  output$table <- DT::renderDataTable({
    req(res_mod())
    res_mod()
  })
}

shinyApp(ui, server)

Note data = mpg_filter (the reactive itself, not a call to it) in callModule(module = selectizeGroupServer)


Outdated answer

The difficulty stems from the fact that selectizeGroupServer does not accept a reactive as the data argument. If it did, it would be simpler. Here is a workaround:

server <- function(input, output, session) {
  mpg_filter <- reactive({
    mpg %>%
      filter(mpg$manufacturer %in% input$car_select)
  })
  
  res_mod <- reactive({})
  
  observe({
    res_mod <<- callModule(
      module = selectizeGroupServer,
      id = "my-filters",
      data = mpg_filter(),
      vars = c("manufacturer", "model", "trans", "class")
    )
  })
  
  output$table <- renderDataTable(res_mod())
}

Here is another one:

server <- function(input, output, session) {
  mpg_filter <- reactive({
    mpg %>%
      filter(mpg$manufacturer %in% input$car_select)
  })
  
  
  res_mod <- reactive({
    callModule(
      module = selectizeGroupServer,
      id = "my-filters",
      data = mpg_filter(),
      vars = c("manufacturer", "model", "trans", "class")
    )
  })
  
  output$table <- renderDataTable(res_mod()())
}

Note the only change: res_mod()(). This is because res_mod() itself is a reactive, since callModule is wrapped in reactive (not just res_mod itself, but the resulting call), so we have to call it twice like res_mod()().
This doesn't happen in the first suggestion, but I had to hack a bit with the initialization of res_mod, and then <<-, to avoid a bug when res_mod is called while still undefined.
I would still go with the first, since res_mod()() is too far from idiomatic Shiny code.

Upvotes: 3

Related Questions