Reputation: 552
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
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