0

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 Rstudio Community

bretauv
  • 7,756
  • 2
  • 20
  • 57

1 Answers1

1

UPDATE: This app will create 3 textInputs in a UI module and return a vector of the textInput values extracted using a server module and display in the UI. Some of this original example has been slightly modified or removed to highlight the answer of returning a vector of values from inputs created in a module.

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)
bs93
  • 1,236
  • 6
  • 10
  • This is not my question. As I said in my post, I know how to generate a reactive number of `textInput`s but I didn't put it in my post because it would add complexity for nothing. My question is: how can I return the values of the `textInput`s (which are in a module) as a vector? Normally, there is nothing to change in the overall structure of my example but you can modify the `ui` and `server` part of the module. – bretauv May 17 '20 at 08:46
  • Ah, gotcha. I updated the answer to show what you just described - returning a vector of textInputs values from a module. I simplified the example to only include the textInput UI and output vector. – bs93 May 17 '20 at 17:48
  • Is there any way to do this with a list of reactives for each input instead of a reactive for a whole list? Like in the official example... `list(a = reactive({input$a}), b = reactive({input$b}), ... )`? – Saren Tasciyan Nov 12 '22 at 13:23