r语言 - 通过插入UI重置动态生成的小部件的输入字段



我正在尝试开发一个闪亮的应用程序,它是更大形式的一部分。特别是,对于此模块,用户可以动态添加(通过插入UI(和删除(通过删除UI(具有与前一行完全相同的小部件的新行。此外,每个新小部件都将包含上一行小部件的完全相同选择,这要归功于 Eli Berkow 为最后一个功能找到了解决方案。

理想情况下,在用户提交答案后,将调用放置在observeEvent()内的shinyjs包的reset()函数来重置每个字段的输入。 这适用于"静态"小部件(此示例中未包含(,但我找不到重置动态生成的小部件的输入字段的方法。

我尝试将每一行分配给不同的div(),并在observeEvent()中使用for循环来重置每个div()中存在的输入,但只清理了一些字段。此外,理想情况下,如果按钮不仅可以重置字段,还可以删除用户添加的每一行并从 0 重新开始编号,那就更好了。下面是一些代码,其中 UI 中插入了一个重置按钮,但仍然没有任何功能。


library(shiny)
library(shinyjs)
###= UI
ui <- fluidPage(
br(),
useShinyjs(),
br(),
fluidRow(
column(width = 3,
align = "center",
h5("Letters")
),
column(width = 3,
align = "center",
h5("Numbers")
)
),
br(),
fluidRow(
column(width = 12,
tags$div(id = "amr_test_placeholder")
)
),
fluidRow(
br(),
# "+" and "-" buttons
column(width = 12,
actionButton(inputId = "add_amr_test",
label = icon(name = "plus",
lib = "font-awesome")),
actionButton(inputId = "remove_amr_test",
label = icon(name = "times",
lib = "font-awesome")),
actionButton(inputId = "reset_button",
label = "RESET FIELDS")
)
),
br(),
br(),
fluidRow(
column(width = 6,
tableOutput(outputId = "show_table")
)
)
)
###= SERVER
server <- function(input, output, session) {
observe({
toggleState(id = "remove_amr_test",
condition = input$add_amr_test >= input$remove_amr_test)
})

amr_test_values <- reactiveValues(val = 0,
ignore = 0)

### Defined the input number to count every row
input_number <- reactive({
input_number <- input$add_amr_test - input$remove_amr_test + 1
return(input_number)
})


observeEvent(input$add_amr_test, {
amr_test_divId <- length(amr_test_values$val) + 1
###= Animal species
if (!is.null(eval(parse(text = paste0("input$letters_", input_number() - 1))))) {
letters_value = eval(parse(text = paste0("input$letters_", input_number() - 1)))
} else {
letters_value = ""
}
###= Animal sample type
if (!is.null(eval(parse(text = paste0("input$numbers_", input_number() - 1))))) {
numbers_value = eval(parse(text = paste0("input$numbers_", input_number() - 1)))
} else {
numbers_value = ""
}
###= Insert dynamic UI
insertUI(
selector = "#amr_test_placeholder",
where = "beforeBegin",
ui = tags$div(id = amr_test_divId,
tags$head(tags$style(HTML(".shiny-split-layout > div {overflow: visible;}"))),
br(),
fluidRow(
column(width = 3,
splitLayout(cellWidths = c("18%", "82%"),
h5(paste0(input_number(), ". ")),
selectizeInput(inputId = paste0("letters_",
   input_number()),
label =  NULL,
choices = c("A" = "",
"A",
"B",
"C",
"D",
"E",
"F",
"F"),
selected = letters_value,
width = "100%",
options = list(create = TRUE))
)
),
column(width = 3,
selectizeInput(inputId = paste0("numbers_",
input_number()),
label = NULL,
choices = list("1" = "",
"1" = "1",
"2" = "2",
"3" = "3",
"4" = "4",
"5" = "5"),
selected = numbers_value,
width = "100%")
)
)
)
)
amr_test_values$val <- c(amr_test_values$val,
amr_test_divId)
}, ignoreNULL = FALSE)
###= Remove dynamic UI
observeEvent(input$remove_amr_test, {
removeUI(
selector = paste0('#', amr_test_values$val[length(amr_test_values$val)])
)
amr_test_values$val <- amr_test_values$val[-length(amr_test_values$val)]
})



###= Dataset to check the dynamic updates of the responses
response <- reactive({
if (input_number() != 0) {
response <- data.frame("Letters" = sapply(X = 1:input_number(),
FUN = function(i) {
input[[paste0("letters_", i)]]
}),
"Numbers" = sapply(X = 1:input_number(),
FUN = function(i) {
input[[paste0("numbers_", i)]]
})
)
return(response)
} else {
response <- NULL
}
})

output$show_table <- renderTable({
response()
})
}

###= Launch App
shinyApp(ui = ui, server = server)

预期结果可以在以下链接中看到。

谢谢!

编辑:

Eli Berkow对我之前版本的问题给出的答案非常有效,所以我将其标记为正确。

我已经更新了代码,以便了解当应用程序启动时自动显示第一行小部件时,Eli 的脚本应该如何工作。我不明白是否要修改与反应值或最后一个观察事件相关的内容。因此,在此版本的脚本中,我添加了自动显示第一行的函数。什么将改编 Eli 的代码?

p.s.:我在小部件下添加了一个反应式数据集,以实际查看值是否存储良好(只是检查脚本是否正常工作(。

谢谢!

见下文:

library(shiny)
library(shinyjs)
###= UI
ui <- fluidPage(
br(),
useShinyjs(),
br(),
fluidRow(
column(width = 3,
align = "center",
h5("Letters")
),
column(width = 3,
align = "center",
h5("Numbers")
)
),
br(),
fluidRow(
column(width = 12,
tags$div(id = "amr_test_placeholder")
)
),
fluidRow(
br(),
# "+" and "-" buttons
column(width = 12,
actionButton(inputId = "add_amr_test",
label = icon(name = "plus",
lib = "font-awesome")),
actionButton(inputId = "remove_amr_test",
label = icon(name = "times",
lib = "font-awesome")),
actionButton(inputId = "reset_button",
label = "RESET FIELDS")
)
),
br(),
br()
)
###= SERVER
server <- function(input, output, session) {
observe({
toggleState(id = "remove_amr_test",
condition = input$add_amr_test > input$remove_amr_test + amr_test_values$reset)
toggleState(id = "reset_button",
condition = input$add_amr_test > input$remove_amr_test + amr_test_values$reset)
})

amr_test_values <- reactiveValues(val = 0,
reset = 0)

### Defined the input number to count every row
input_number <- reactive({
input_number <- input$add_amr_test - input$remove_amr_test - amr_test_values$reset
return(input_number)
})


observeEvent(input$add_amr_test, {
amr_test_divId <- length(amr_test_values$val) + 1
###= Animal species
if (!is.null(eval(parse(text = paste0("input$letters_", input_number() - 1))))) {
letters_value = eval(parse(text = paste0("input$letters_", input_number() - 1)))
} else {
letters_value = ""
}
###= Animal sample type
if (!is.null(eval(parse(text = paste0("input$numbers_", input_number() - 1))))) {
numbers_value = eval(parse(text = paste0("input$numbers_", input_number() - 1)))
} else {
numbers_value = ""
}
###= Insert dynamic UI
insertUI(
selector = "#amr_test_placeholder",
where = "beforeBegin",
ui = tags$div(id = amr_test_divId,
tags$head(tags$style(HTML(".shiny-split-layout > div {overflow: visible;}"))),
br(),
fluidRow(
column(width = 3,
splitLayout(cellWidths = c("18%", "82%"),
h5(paste0(input_number(), ". ")),
selectizeInput(inputId = paste0("letters_",
           input_number()),
label =  NULL,
choices = c("A" = "",
      "A",
      "B",
      "C",
      "D",
      "E",
      "F",
      "F"),
selected = letters_value,
width = "100%",
options = list(create = TRUE))
)
),
column(width = 3,
selectizeInput(inputId = paste0("numbers_",
input_number()),
label = NULL,
choices = list("1" = "",
"1" = "1",
"2" = "2",
"3" = "3",
"4" = "4",
"5" = "5"),
selected = numbers_value,
width = "100%")
)
)
)
)
amr_test_values$val <- c(amr_test_values$val,
amr_test_divId)
})
###= Remove dynamic UI
observeEvent(input$remove_amr_test, {
removeUI(
selector = paste0('#', amr_test_values$val[length(amr_test_values$val)])
)
amr_test_values$val <- amr_test_values$val[-length(amr_test_values$val)]
})
observeEvent(input$reset_button, {
for(remove_value in 2:max(amr_test_values$val)) {
removeUI(
selector = paste0('#', remove_value)
)
}
amr_test_values$reset <- input$add_amr_test - input$remove_amr_test
amr_test_values$val <- 0
})
}

###= Launch App
shinyApp(ui = ui, server = server)

我在这里添加了一个reset反应值:

observe({
toggleState(id = "remove_amr_test",
condition = input$add_amr_test > input$remove_amr_test + amr_test_values$reset)
toggleState(id = "reset_button",
condition = input$add_amr_test > input$remove_amr_test + amr_test_values$reset)
})

amr_test_values <- reactiveValues(val = 0,
reset = 0)

### Defined the input number to count every row
input_number <- reactive({
input_number <- input$add_amr_test - input$remove_amr_test - amr_test_values$reset
return(input_number)
})

然后这个observeEvent

observeEvent(input$reset_button, {
for(remove_value in 2:max(amr_test_values$val)) {
removeUI(
selector = paste0('#', remove_value)
)
}
amr_test_values$reset <- input$add_amr_test - input$remove_amr_test
amr_test_values$val <- 0
})

更新

根据您的编辑。

library(shiny)
library(shinyjs)
###= UI
ui <- fluidPage(
br(),
useShinyjs(),
br(),
fluidRow(
column(width = 3,
align = "center",
h5("Letters")
),
column(width = 3,
align = "center",
h5("Numbers")
)
),
br(),
fluidRow(
column(width = 12,
tags$div(id = "amr_test_placeholder")
)
),
fluidRow(
br(),
# "+" and "-" buttons
column(width = 12,
actionButton(inputId = "add_amr_test",
label = icon(name = "plus",
lib = "font-awesome")),
actionButton(inputId = "remove_amr_test",
label = icon(name = "times",
lib = "font-awesome")),
actionButton(inputId = "reset_button",
label = "RESET FIELDS")
)
),
br(),
br(),
fluidRow(
column(width = 6,
tableOutput(outputId = "show_table")
)
)
)
###= SERVER
server <- function(input, output, session) {
observe({
toggleState(id = "remove_amr_test",
condition = input$add_amr_test > input$remove_amr_test + amr_test_values$reset)
toggleState(id = "reset_button",
condition = input$add_amr_test > input$remove_amr_test + amr_test_values$reset)
})

amr_test_values <- reactiveValues(val = 0,
reset = 0)

### Defined the input number to count every row
input_number <- reactive({
input_number <- input$add_amr_test - input$remove_amr_test - amr_test_values$reset + 1
return(input_number)
})


observeEvent(input$add_amr_test, {
amr_test_divId <- length(amr_test_values$val) + 1
###= Animal species
if (!is.null(eval(parse(text = paste0("input$letters_", input_number() - 1))))) {
letters_value = eval(parse(text = paste0("input$letters_", input_number() - 1)))
} else {
letters_value = "A"
}
###= Animal sample type
if (!is.null(eval(parse(text = paste0("input$numbers_", input_number() - 1))))) {
numbers_value = eval(parse(text = paste0("input$numbers_", input_number() - 1)))
} else {
numbers_value = 1
}
###= Insert dynamic UI
insertUI(
selector = "#amr_test_placeholder",
where = "beforeBegin",
ui = tags$div(id = amr_test_divId,
tags$head(tags$style(HTML(".shiny-split-layout > div {overflow: visible;}"))),
br(),
fluidRow(
column(width = 3,
splitLayout(cellWidths = c("18%", "82%"),
h5(paste0(input_number(), ". ")),
selectizeInput(inputId = paste0("letters_",
   input_number()),
label =  NULL,
choices = c("A" = "",
"A",
"B",
"C",
"D",
"E",
"F",
"F"),
selected = letters_value,
width = "100%",
options = list(create = TRUE))
)
),
column(width = 3,
selectizeInput(inputId = paste0("numbers_",
input_number()),
label = NULL,
choices = list("1" = "",
"1" = "1",
"2" = "2",
"3" = "3",
"4" = "4",
"5" = "5"),
selected = numbers_value,
width = "100%")
)
)
)
)
amr_test_values$val <- c(amr_test_values$val,
amr_test_divId)
}, ignoreNULL = FALSE)
###= Remove dynamic UI
observeEvent(input$remove_amr_test, {
removeUI(
selector = paste0('#', amr_test_values$val[length(amr_test_values$val)])
)
amr_test_values$val <- amr_test_values$val[-length(amr_test_values$val)]
})

observeEvent(input$reset_button, {
for(remove_value in 3:max(amr_test_values$val)) {
removeUI(
selector = paste0('#', remove_value)
)
}
amr_test_values$reset <- input$add_amr_test - input$remove_amr_test
amr_test_values$val <- c(0, 2)
})

###= Dataset to check the dynamic updates of the responses
response <- reactive({
if (input_number() != 0 & !is.null(input[[paste0("letters_", input_number())]])) {
response <- data.frame("Letters" = sapply(X = 1:input_number(),
FUN = function(i) {
input[[paste0("letters_", i)]]
}),
"Numbers" = sapply(X = 1:input_number(),
FUN = function(i) {
input[[paste0("numbers_", i)]]
})
)
return(response)
} else {
response <- NULL
}
})

output$show_table <- renderTable({
response()
})
}

###= Launch App
shinyApp(ui = ui, server = server)

最新更新