CephBirk
CephBirk

Reputation: 6710

Collect All user inputs throughout the Shiny App

Is there a way to show the value from textInput() elsewhere in the UI without having to go through server.R with something very verbose like the following?

ui.R

library(shiny)
shinyUI(
  fluidPage(
  textInput('text_in', label = 'Write text here'),

  # elsewhere in the UI...

  textOutput('text_out')
))

server.R

library(shiny)
shinyServer(function(input, output) {
  output$text_out = renderText(input$text_in)
})

It's not too bad for this example, but it becomes very verbose when I need to do it many times. My desire is to collect all the inputs the user enters throughout the app and compile them into a nice table at the end so they can confirm everything is laid out right.

I've seen you can reference input elements without going through the server when using a JavaScript expression in conditionalPanel() but I'm not sure how to implement that outside of this specific instance.

Upvotes: 17

Views: 9773

Answers (4)

BSCowboy
BSCowboy

Reputation: 347

Borrowing from both Pork Chop and mysteRious, here's a solution that works for multiple types of text & number inputs in shiny.

library(shiny)

AdvRchp3 <- "While you’ve probably already used many (if not all) 
of the different types of vectors, you may not have thought 
deeply about how they’re interrelated. In this chapter, 
I won’t cover individual vectors types in too much detail, 
but I will show you how all the types fit together as a whole. 
If you need more details, you can find them in R’s documentation."

ui <- fluidPage(
  fluidRow(
    h4("Text Inputs"),
    textInput("text_input", "Input some Text", value = "some text"),
    passwordInput("password_input", "Input a Password", value = "1234"),
    textAreaInput("text_area_input", "Input lots of Text", rows = 3, value = AdvRchp3)
  ),
  fluidRow(
    h4("Numeric Inputs"),
    numericInput("numeric_input", "Number 1", value = 1, min = 0, max = 100),
    sliderInput("slider_input_single", "Number 50", value = 50, min = 0, max = 100),
    sliderInput("slider_input_ranges", "Range 10 to 20", value = c(10, 20), min = 0, max = 100)
  ),
  fluidRow(
    tableOutput("show_inputs")
  )
)  

server <- function(input, output, session) {
  all_inputs <- reactive({
    input_df <- NULL
    df_row <- NULL
    for(i in 1:length(names(input))){
      df_row <- as.data.frame(cbind(names(input)[i], input[[names(input)[i]]]))
      input_df <- as.data.frame(dplyr::bind_rows(input_df, df_row))
    }
    names(input_df) <- c("input_id", "input_val")
    input_df
  })
  
  output$show_inputs <- renderTable({
    all_inputs()
  })
}

shinyApp(ui, server)

notice: the rbind is now dplyr::bind_rows, but plyr::rbind.fill will also work.

Upvotes: 1

mysteRious
mysteRious

Reputation: 4294

If the Shiny inputs all have different lengths and the above does not work (e.g. if you have combination of radio buttons, checkboxgroup, textInput, etc.) this will work and can produce a table of variable:value that you can parse later:

AllInputs <- reactive({
  myvalues <- NULL
  newvalues <- NULL
  for(i in 1:length(names(input))){
    newvalues <- paste(names(input)[i], input[[names(input)[i]]], sep=":")
    myvalues <- append(myvalues, newvalues)
  }
  myvalues
})

output$show_inputs <- renderTable({
  AllInputs()
})

Upvotes: 1

Victorp
Victorp

Reputation: 13856

For accessing all inputs, you can use reactiveValuesToList server-side. You can access input values via Javascript Events like below (I have taken the example from @Pork Chop) :

library(shiny)

ui <- basicPage(

  fluidRow(
    column(
      width = 6,
      textInput('a', 'Text A',"a1"),
      textInput('b', 'Text B',"b1"),
      textInput('c', 'Text A',"c1"),
      textInput('d', 'Text B',"d1"),
      textInput('e', 'Text A',"e1"),
      textInput('f', 'Text B',"f1")
    ),
    column(
      width = 6,
      tags$p("Text A :", tags$span(id = "valueA", "")),
      tags$script(
        "$(document).on('shiny:inputchanged', function(event) {
          if (event.name === 'a') {
            $('#valueA').text(event.value);
          }
        });
        "
      ),
      tableOutput('show_inputs')
    )
  )
)

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

  AllInputs <- reactive({
    x <- reactiveValuesToList(input)
    data.frame(
      names = names(x),
      values = unlist(x, use.names = FALSE)
    )
  })

  output$show_inputs <- renderTable({
    AllInputs()
  })
})
shinyApp(ui = ui, server = server)

Upvotes: 31

Pork Chop
Pork Chop

Reputation: 29387

Since your overall objective is to collect all the user inputs and then compile them into a table I will show you how to achieve that with example below. As you can see all of the input variables can be accessed by names from server. I kept them in a reactive just in case you need it for further analysis or for some renderUI functionality.

#rm(list=ls())
library(shiny)

ui <- basicPage(
  textInput('a', 'Text A',"a1"),
  textInput('b', 'Text B',"b1"),
  textInput('c', 'Text A',"c1"),
  textInput('d', 'Text B',"d1"),
  textInput('e', 'Text A',"e1"),
  textInput('f', 'Text B',"f1"),
  tableOutput('show_inputs')
)
server <- shinyServer(function(input, output, session){

  AllInputs <- reactive({
    myvalues <- NULL
    for(i in 1:length(names(input))){
      myvalues <- as.data.frame(rbind(myvalues,(cbind(names(input)[i],input[[names(input)[i]]]))))
    }
    names(myvalues) <- c("User Input","Last Value")
    myvalues
  })

  output$show_inputs <- renderTable({
    AllInputs()
  })
})
shinyApp(ui = ui, server = server)

enter image description here

Upvotes: 7

Related Questions