Search code examples
rmoduleshiny-servershiny

Shiny Modules: how to access the input$ of a looped Shiny Module?


I'm wrapping my head around Shiny Module nesting and have this problem.

The code for an example Shiny app with the issue is available here. Copy-pasting into an .R file and running in RStudio should replicate it.

I'm trying to make a helper function that will filter/aggregate any data.frame. I am as far as getting some dynamic SelectInputs which is already useful, but I now want to put those SelectInputs into a loop so I can subset a data.frame.

The problem seems to be that the inputs that are generated within the Shiny server loop can not be accessed via normal Shiny modules means, and the syntax for finding their names eludes me. The issue lies within these lines:

  new_data <- reactive({
    old_data <- the_data()
    for(i in seq_along(aggs)){

      str(i) ## debug to check its in loop

      agg <- aggs[i]

      ## How to access the dynamic_select inputs selected?
      inputA <- input[[agg]]  # is NULL?
      old_col <- old_data[[agg]] 

      str(inputA) ## debug - NULL should hold values of dynamic inputs

      new_data <- old_data[inputA %in% old_col,]

      old_data <- new_data

    }

    new_data

  })

Does anyone have an idea on how to access the selected values that should be appearing in variable inputA ?


Solution

  • Joe helped in the Shiny Google Group, the Gist now has a working version: https://gist.github.com/MarkEdmondson1234/7565787bb020b1c7cb691cf80e816d68

    Here was his answer:

    The general rule for modules is that you can only access the value of a moduleUI's input, in the corresponding module server function. In this case, you can only access the value of dynamicSelectInput from within dynamicSelect. If you want to then make that value available to other modules, then you have to return it as a reactive from the module server function. In this case, that means that the dynamicSelect function should end with this line:

      return(reactive(input$dynamic_select))
    

    ("return" is optional but I think it helps make explicit the fact that reactive(input$dynamic_select) is the return value.)

    Then, in outerTable, you could do something like this instead of your for-loop:

      selectResults <- lapply(setNames(aggs, aggs), function(agg) {
        callModule(module = dynamicSelect,
          id = agg,
          the_data = the_data,
          column = agg)
      })
    

    Now selectResults is a named list, each element being a reactive expression (so selectResults[[agg]]() to retrieve a value).