问题
I'm trying to dynamically add new variables to my shiny app which is working but if I start editing one, the values (text and numeric) reset each time I then add an additional variable. This example works without needing a for loop using reactiveValuesToList()
but when I apply it to my code, it doesn't work. Here is my working example:
library(shiny)
dist <- c("Normal", "Gamma")
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) {
fluidRow(
selectInput(inputId = paste0("news", i),
label = paste0("Variable ", i),
choices = dist),
conditionalPanel(
condition = sprintf("input.%s=='Normal'", paste0("news", i)),
textInput("txt", "Text input:", paste0("var", i)),
column(width = 3, numericInput('normal_mean', 'Mean', value = '0')), column(width = 3, numericInput('normal_sd', 'Standard deviation', value = '1'))),
conditionalPanel(
condition = sprintf("input.%s=='Gamma'", paste0("news", i)),
textInput("txt", "Text input:", paste0("var", i)),
column(width = 3, numericInput('gamma_shape', 'Shape', value = '0')), column(width = 3, numericInput('gamma_scale', 'Scale', value = '1')))
)
})
})
}
})
output$textbox_ui <- renderUI({ textboxes() })
})
shinyApp(ui, server)
Now if I try and add AllInputs()[[]]
to textInput
it doesn't keep the text in the conditionalPanel
call:
conditionalPanel(
condition = sprintf("input.%s=='Normal'", paste0("news", i)),
textInput("txt", "Text input:", AllInputs()[[paste0("var", i)]]),
column(width = 3, numericInput('normal_mean', 'Mean', value = '0')), column(width = 3, numericInput('normal_sd', 'Standard deviation', value = '1')))
I'm also not sure how to include AllInputs()[[]]
to the numeric values so that they dont change.
I think the problem is because of my condition
line within conditionalPanel
but can't figure it out, any suggestions? thanks
回答1:
You should consider using modules and insertUI
/ removeUI
. Clicking on the buttons will not reset your changes on the inputs you already called. Here, you just have inputs so you only need to call the function add_box
I created, but if you want to add outputs in the module, then you will need to use the function callModule
in observeEvent
. This is explained in the article I refer to.
This is not the method you suggested but it works.
library(shiny)
dist <- c("Normal", "Gamma")
add_box <- function(id){
ns <- NS(id)
tags$div(id = paste0("new_box", id),
selectInput(inputId = ns("news"),
label = paste0("Variable ", id),
choices = dist),
conditionalPanel(
condition = "input.news=='Normal'",
ns = ns,
textInput(ns("txt"), "Text input:", paste0("var", id)),
column(width = 3, numericInput(ns('normal_mean'), 'Mean', value = '0')),
column(width = 3, numericInput(ns('normal_sd'), 'Standard deviation', value = '1'))),
conditionalPanel(
condition = "input.news=='Gamma'",
ns = ns,
textInput(ns("txt"), "Text input:", paste0("var", id)),
column(width = 3, numericInput(ns('gamma_shape'), 'Shape', value = '0')),
column(width = 3, numericInput(ns('gamma_scale'), 'Scale', value = '1')))
)
}
ui <- shinyUI(fluidPage(
sidebarPanel(
actionButton("add_btn", "Add Textbox"),
actionButton("rm_btn", "Remove Textbox"),
textOutput("counter")
),
mainPanel(column(width = 12, id = "column"))
))
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
insertUI(selector = "#column",
where = "beforeEnd",
ui = add_box(counter$n)
)
})
observeEvent(input$rm_btn, {
if (counter$n > 0) {
removeUI(selector = paste0("#new_box", counter$n))
counter$n <- counter$n - 1
}
})
output$counter <- renderPrint(print(counter$n))
})
shinyApp(ui, server)
来源:https://stackoverflow.com/questions/60818727/shiny-dynamically-add-input-fields-and-data-without-getting-re-rendered