Sean Sinykin
Sean Sinykin

Reputation: 552

How do I add insertUI() output to renderText() ouput in R Shiny?

I am developing a shiny app to provide automation for system development, and I need a way to add text boxes for user input, and add the resulting user input to renderText() output. I am not sure if there is a way to loop through reactive values, so for now I am forced to make specific calls to labels in the textInput() results. Code is below, note that the part that needs to be changed is the output$value part at bottom of server section:

library(shiny)
ui <- fluidPage(
            fluidRow(
                column(6,
                    textInput("mainDesc1", label = "Main Description", value = "", width = '100%')
                    ),
                column(1,
                    actionButton(inputId = 'insertBtn', label = "More")
                    ),
                column(1,
                    actionButton(inputId = 'removeBtn', label = "Less")
                    )
                ),
            tags$div(id = 'placeholder'),
            fluidRow(column(12, verbatimTextOutput("value")))
)

server <- function(input, output) {
    ## keep track of elements inserted and not yet removed
    inserted <- c()
    #btn <- 1
    observeEvent(input$insertBtn, {
        btn <- input$insertBtn + 1
        id <- paste0("mainDesc", btn)
        insertUI(
            selector = '#placeholder',
        ## wrap element in a div with id for ease of removal
            ui = tags$div(
                tags$p(fluidRow(
                    column(6,
                        textInput(paste("mainDesc", btn + 1, sep = ""), label = "", value = "", width = '100%')
                        )
                    )
                ),
                id = id
                )
            )
        inserted <<- c(id, inserted)
    })

    observeEvent(input$removeBtn, {
        removeUI(
        ## pass in appropriate div id
          selector = paste0('#', inserted[length(inserted)])
        )
        inserted <<- inserted[-length(inserted)]
    })

    output$value <- renderText({ noquote(paste(input[[paste("mainDesc", 1, sep = "")]], "\n",
                                               input[[paste("mainDesc", btn + 1, sep = "")]], sep = ""))
                                               })
    }
shinyApp(ui = ui, server = server)

How can I loop over the results of the userInput() boxes that pop up as a result of

textInput(paste("mainDesc", btn + 1, sep = ""), label = "", value = "", width = '100%')

to paste line-by-line all existing outputs of the above? Essentially, what I am looking for is if the user inputs "1st line" in the first "Main Description" text box, clicks the "More" button to add "2nd line" in the text box that pops up, clicks more again and types "3rd line" in the popup text box the renderText() box outputs:

1st line
2nd line
3rd line

If more text boxes are added, the user input should be added line-by-line to the renderText() output. Thanks!

Upvotes: 0

Views: 791

Answers (1)

cmaher
cmaher

Reputation: 5225

Try making btn a reactiveValue:

vals <- reactiveValues(btn = 1)
# reference elsewhere in your app as vals$btn

See what seems to be working code here:

library(shiny)

ui <- fluidPage(
  fluidRow(
    column(6,
           textInput("mainDesc1", label = "Main Description", value = "", width = '100%')
    ),
    column(1,
           actionButton(inputId = 'insertBtn', label = "More")
    ),
    column(1,
           actionButton(inputId = 'removeBtn', label = "Less")
    )
  ),
  tags$div(id = 'placeholder'),
  fluidRow(column(12, verbatimTextOutput("value", placeholder = T)))
)

server <- function(input, output) {
  ## keep track of elements inserted and not yet removed
  vals <- reactiveValues(btn = 0)

  observeEvent(input$insertBtn, {
    vals$btn <- vals$btn + 1
    insertUI(
      selector = '#placeholder',
      ## wrap element in a div with id for ease of removal
      ui = tags$div(
        id = paste0('line', vals$btn),
        tags$p(fluidRow(
          column(6,
                 textInput(paste("mainDesc", vals$btn + 1, sep = ""), label = paste("Line", vals$btn), value = "", width = '100%')
                 )
          )
        )
      )
    )
  })

  observeEvent(input$removeBtn, {
    removeUI(
      ## pass in appropriate div id
      selector = paste0('#line', vals$btn)
    )
    vals$btn <- vals$btn - 1
  })

  output$value <- renderText({ 
    msg <- c(input[["mainDesc1"]])
    if (vals$btn > 0) {
      for (i in 1:vals$btn) {
        msg <- c(msg, input[[paste0("mainDesc", i + 1)]])
      }
      msg <- paste(msg, collapse = "\n")  
    }
  })
}

shinyApp(ui = ui, server = server)

Upvotes: 1

Related Questions