Я хочу собирать индивидуальную информацию (имя и возраст) в качестве пользовательского ввода с прикрепленным демонстрационным кодом. Начальное количество лиц равно 1, и когда пользователь увеличивает/уменьшает значение количества лиц, он автоматически добавляет/уменьшает соответствующие строки для сбора индивидуальной информации. Мой вопрос заключается в том, как избежать стирания текущей входной информации при увеличении/уменьшении количества людей. Например, скриншот 1 показывает информацию о человеке 1, введенную пользователем (мной). Когда я изменил значения количества лиц на 2, информация, которую я ввел ранее, была стерта (скриншот 2), и мне пришлось повторно ввести информацию для человека 1. Я ожидаю, что будет похоже на скриншот 3 (информация для человека 1). не уничтожается), когда я увеличиваю количество особей до 2. Может ли кто-нибудь помочь мне с этим? Спасибо!
Обновление от 15.05.2022
Ответ на обновление с использованием isolate - это то, что я ищу. Еще раз спасибо за помощь от @jpdugo17.
Пример кода
library(shiny)
ui <- fluidPage(
tabsetPanel(
tabPanel(
h4("Individual Information"),
fluidRow(column(4,numericInput("ninds",
label = "Number of individuals",
value = 1, min = 1, step = 0.5, width = "300px"))),
br(),
fluidRow(column(2,align = "center",strong("Individual #")),
column(5,align = "center",strong("Individual Name")),
column(5,align = "center",strong("Age"))),
fluidRow(
column(2,wellPanel(uiOutput("indNum"))),
column(5,wellPanel(uiOutput("Name"))),
column(5,wellPanel(uiOutput("Age"))))
)
)
)
server <- function(input, output) {
# create reactive variable paste0("individualNum", i) for further using
output$indNum <- renderUI({
num <- as.integer(input$ninds)
req(num)
lapply(1:num, function(i) {
numericInput(paste0("individualNum", i), value = i, label = "", max = i, min = i)
})
})
# create reactive variable paste0("name", i) for further using
output$Name <- renderUI({
num <- as.integer(input$ninds)
req(num)
lapply(1:num, function(i) {
textInput(paste0("name", i), label = "")
})
})
# create reactie variable paste0("age", i) for further using
output$Age <- renderUI({
num <- as.integer(input$ninds)
req(num)
lapply(1:num, function(i) {
numericInput(paste0("age", i), label = "", value = 0)
})
})
}
# Run the app ----
shinyApp(ui, server)
В моем случае, я бы сказал, обычно менее 15 человек. @jpdugo17
Простейшим случаем было бы инициализировать приложение с входными данными для 15 человек, но отображать или скрывать их по запросу пользователя. Другой альтернативой является использование функции insertUI. Какое решение вы предпочитаете?
Спасибо. @jpdugo17. Первый вариант не подходит для моего случая. Что касается insertUI, я только что проверил, и мне кажется, что он добавит независимый объект пользовательского интерфейса. В моем приложении мне понадобятся реактивные переменные, созданные на сервере (например, numericInput(paste0("age", i), label = "", value = 0)) для последующего использования. Будет ли работать этот insertUI? Кроме того, я заметил, что в некоторых сообщениях вставка UI сочетается с модулями, будет ли это работать в моем случае? Спасибо за помощь.





Редактировать:
Мы можем использовать isolate с текущим значением ввода и передать его в качестве аргумента значения в numericInput или textInput. Это будет работать, потому что любой ввод, который еще не существует, даст NULL.
server <- function(input, output) {
# create reactive variable paste0("individualNum", i) for further using
num <- reactive({
req(input$ninds)
input$ninds
})
output$indNum <- renderUI({
lapply(1:num(), function(i) {
numericInput(paste0("individualNum", i), value = i, label = "", max = i, min = i)
})
})
# create reactive variable paste0("name", i) for further using
output$Name <- renderUI({
lapply(1:num(), function(i) {
textInput(paste0("name", i), label = "", value = isolate(input[[paste0("name", i)]]))
})
})
# create reactie variable paste0("age", i) for further using
output$Age <- renderUI({
lapply(1:num(), function(i) {
numericInput(paste0("age", i), label = "", value = isolate(input[[paste0("age", i)]]))
})
})
}
Оригинальный ответ с использованием insertUI:
Мы можем реализовать подобную логику: создайте счетчик для хранения текущего номера ввода, сделайте две кнопки, одну для добавления и другую для удаления входов. Нам придется обернуть каждый ввод div с уникальным идентификатором (поскольку функции ввода обычно добавляют несколько элементов).
library(shiny)
library(purrr)
ui <- fluidPage(
tabsetPanel(
tabPanel(
h4("Individual Information"),
fluidRow(
column(
4, fluidRow(
column(6, numericInput("ninds",
label = "Number of individuals",
value = 1, min = 1, step = 0.5, width = "300px"
)), column(3, actionButton("add_ui", "Add Individual", style = "background-color: green;")),
column(3, actionButton("remove_ui", "Remove Individual", style = "background-color: red;"))
)
)
),
br(),
fluidRow(
column(2, align = "center", strong("Individual #")),
column(5, align = "center", strong("Individual Name")),
column(5, align = "center", strong("Age"))
),
fluidRow(
column(2, wellPanel(id = "IndNumber")),
column(5, wellPanel(id = "Name")),
column(5, wellPanel(id = "Age"))
)
)
)
)
server <- function(input, output) {
# track the number of inputs
ui_counter <- reactiveVal(1)
observeEvent(input$add_ui, {
div_nms <- map_chr(c("individualNum", "name", "age"), ~ paste0("div", .x, ui_counter()))
# individual number
insertUI(
selector = "#IndNumber",
ui = div(
id = div_nms[[1]],
numericInput(paste0("individualNum", ui_counter()),
label = "",
value = ui_counter(),
min = ui_counter(),
max = ui_counter()
)
)
)
# name input
insertUI(
selector = "#Name",
ui = div(id = div_nms[[2]], textInput(paste0("name", ui_counter()),
label = ""
))
)
# age input
insertUI(
selector = "#Age",
ui = div(id = div_nms[[3]], numericInput(paste0("age", ui_counter()),
label = "",
value = 0
))
)
ui_counter(ui_counter() + 1)
})
# observer to remove the divs containing the inputs
observeEvent(input$remove_ui, {
if (ui_counter() > 1) {
walk(c("individualNum", "name", "age"), ~ removeUI(paste0("#div", .x, ui_counter() - 1)))
ui_counter(ui_counter() - 1)
}
})
}
# Run the app ----
shinyApp(ui, server)
Большой! @jpdugo17. Единственный вопрос, который у меня есть, это то, что текущий «numericInput» не реагирует с «actionButton» или наоборот. Один из способов, который я вижу, - это заменить «numericInput» на «textOutput», который будет зависеть от «actionButton», но это будет однонаправленная зависимость (actionButton влияет на textOutput). Я просто хочу проверить, есть ли лучшие решения, прежде чем я приму ваш ответ. Еще раз спасибо за вашу помощь!
@OceanSky_U Пожалуйста, посмотрите мое редактирование, теперь вы можете выбрать количество людей из числового ввода, как и раньше.
Замечательно! Кажется, «изолировать» — это именно то, что я ищу. Спасибо! @jpdugo17
В среднем, сколько людей будет в приложении в любой момент времени?