16

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.

Pork Chop
  • 28,528
  • 5
  • 63
  • 77
CephBirk
  • 6,422
  • 5
  • 56
  • 74

4 Answers4

28

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)
Victorp
  • 13,636
  • 2
  • 51
  • 55
7

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

Pork Chop
  • 28,528
  • 5
  • 63
  • 77
1

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()
})
mysteRious
  • 4,102
  • 2
  • 16
  • 36
1

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.

BSCowboy
  • 317
  • 4
  • 13