Return the values of a list of inputs from a module

I have a module in which I create a list of inputs based on a reactive value: if this value is 3, then 3 textInputs are created, etc. Until now, when I needed to return inputs/values from a module, I listed all of the inputs/values in return() at the end of the server part of my module (see this article for more details).

But in this situation, since the number of inputs is not constant, I can't list all of the inputs in return(). Therefore, I would like to create a reactive list that I could return.

Consider the example below:

library(shiny)

some_things <- c("drat", "mpg", "cyl")
numtextinputs <- length(some_things)

some_UI <- function(id) {
  ns <- NS(id)
  tagList(
    fluidRow(
      column(
        12,
        lapply(1:numtextinputs, function(x) {
          textInput(ns(some_things[x]),
                    label = some_things[x],
                    value = some_things[x])
        }),
        actionButton(ns("change"), "change inputs")
      )
    )
  )
}

some_server <- function(input, output, session) {
  
  observeEvent(input$change, {
    
    test <- list()
    char_numtextinputs <- as.character(numtextinputs)
    
    for (x in char_numtextinputs) {
      local({
        test[[x]] <- input[[some_things[x]]]
      })
    }
    
    return(reactive({ test }) )
  })
  
}

ui <- fluidPage(
  actionButton("create_ui", "create ui"),
  uiOutput("ui"),
  verbatimTextOutput("display_changes")
)

server <- function(input, output, session) {
  
  observeEvent(input$create_ui, {
    output$ui <- renderUI({
      some_UI("1")
    })
    list_of_variables <- callModule(some_server, "1")
  })

  output$display_changes <- renderText({
    if (exists("list_of_variables")){
      list_of_variables$test()
    }
    else {
      "list_of_variables$test does not exist"
    }
  })
    
}

shinyApp(ui, server)

In this example, clicking on "create ui" generates a list of textInputs. Note that here, the number of textInputs created is constant (I wanted to have a simple example, adding some reactivity in the number of inputs to be created is not very useful).

Expected result: after having generated the list of textInputs, the user can modify the values in those and click on "change inputs" when he/she has finished. The module should then return the values in the textInputs as a vector. The verbatimTextOutput is just here to verify that the values are well returned. Note that the answer should work with any number of textInputs (this is why I tried lists and loop).

Also asked on StackOverflow

Answered by bs93 on StackOverflow:

library(shiny)
library(tidyverse)

some_things <- c("drat", "mpg", "cyl")
numtextinputs <- length(some_things)


some_UI <- function(id) {
  ns <- NS(id)
  tagList(
    fluidRow(
      column(
        12,
        map(some_things, ~textInput(ns(.x), label = .x, value = .x ))
      )
    )
  )
}

some_server <- function(input, output, session) {
  #extract values of all the text boxes without explicitly naming them
  #by using the ids we used to create the textInputs
  test <- reactive({
    map_chr(some_things, ~input[[.x]])
  })

  #return the vector of values from module *note no () are needed after test
  # i.e. return(test) NOT return(test())
  return(test)
}

ui <- fluidPage(

  some_UI("1"),
  verbatimTextOutput("display_changes")
)

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

  list_of_variables <- callModule(some_server, "1")


  output$display_changes <- renderText({

    list_of_variables()


  })

}

shinyApp(ui, server)

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.