I've been trying to find a solution how to add and remove input fields with a button in shiny. I don't have a source code since I haven't made that much progress, but this jQuery example (http://www.mkyong.com/jquery/how-to-add-remove-textbox-dynamically-with-jquery/) gives a good idea on what I'm trying to accomplish. Is this possible in shiny or should I use shinyjs to do this? Thank you in advance!
EDIT: I read the jQuery example a bit more, and added a code snippet doing what I think you were looking for.
I don't know jQuery, so I couldn't make much out of the example link. I took a guess on what you wanted, but I think the key idea is the use of renderUI
and uiOutput
even if my suggestion here misses the point.
To toggle a ui element:
If you specifically don't want to use shinyjs
, you could do something like this:
library(shiny)
ui <- shinyUI(fluidPage(
actionButton("btn", "Toggle Textbox"),
textOutput("btn_val"),
uiOutput("textbox_ui")
))
server <- shinyServer(function(input, output, session) {
output$btn_val <- renderPrint(print(input$btn))
textboxToggle <- reactive({
if (input$btn %% 2 == 1) {
textInput("textin", "Write something:", value = "Hello World!")
}
})
output$textbox_ui <- renderUI({ textboxToggle() })
})
shinyApp(ui, server)
To add and remove elements:
After reading a bit of the jQuery example, I think this is similar to what you were looking for:
library(shiny)
ui <- shinyUI(fluidPage(
sidebarPanel(
actionButton("add_btn", "Add Textbox"),
actionButton("rm_btn", "Remove Textbox"),
textOutput("counter")
),
mainPanel(uiOutput("textbox_ui"))
))
server <- shinyServer(function(input, output, session) {
# Track the number of input boxes to render
counter <- reactiveValues(n = 0)
observeEvent(input$add_btn, {counter$n <- counter$n + 1})
observeEvent(input$rm_btn, {
if (counter$n > 0) counter$n <- counter$n - 1
})
output$counter <- renderPrint(print(counter$n))
textboxes <- reactive({
n <- counter$n
if (n > 0) {
lapply(seq_len(n), function(i) {
textInput(inputId = paste0("textin", i),
label = paste0("Textbox", i), value = "Hello World!")
})
}
})
output$textbox_ui <- renderUI({ textboxes() })
})
shinyApp(ui, server)
The problem with this approach is that each time you press the add or remove button, all of the input boxes get re-rendered. This means that any input you might have had on them disappears.
I think you could get around that by also saving the current input values of the input boxes into a reactiveValues
object, and setting the values from the object as the starting values of the re-rendered input boxes by using the value
option in textInput
. I'll leave the implementation of that for now, though.
Thank you @Mikko Marttila for your answer. I was able to use it for my purpose. Also, referring to the issue of all input boxes getting re-rendered here I found a solution worked from this answer. You can save all user inputs using reactiveValuesToList()
, then call the reactive list accordingly to set every value to the corresponding user's input in the lapply()
statement.
library(shiny)
ui <- shinyUI(fluidPage(
sidebarPanel(
actionButton("add_btn", "Add Textbox"),
actionButton("rm_btn", "Remove Textbox"),
textOutput("counter")
),
mainPanel(uiOutput("textbox_ui"))
))
server <- shinyServer(function(input, output, session) {
# Track the number of input boxes to render
counter <- reactiveValues(n = 0)
# Track all user inputs
AllInputs <- reactive({
x <- reactiveValuesToList(input)
})
observeEvent(input$add_btn, {counter$n <- counter$n + 1})
observeEvent(input$rm_btn, {
if (counter$n > 0) counter$n <- counter$n - 1
})
output$counter <- renderPrint(print(counter$n))
textboxes <- reactive({
n <- counter$n
if (n > 0) {
isolate({
lapply(seq_len(n), function(i) {
textInput(inputId = paste0("textin", i),
label = paste0("Textbox", i),
value = AllInputs()[[paste0("textin", i)]])
})
})
}
})
output$textbox_ui <- renderUI({ textboxes() })
})
shinyApp(ui, server)
EDIT: I wrapped the lapply()
statement in isolate()
because it gets annoying when boxes are being re-rendered as you're trying to type in the field
来源:https://stackoverflow.com/questions/31454185/how-to-add-remove-input-fields-dynamically-by-a-button-in-shiny