Не стирать (введенные пользователем) значения реактивных переменных при изменении входных значений

Я хочу собирать индивидуальную информацию (имя и возраст) в качестве пользовательского ввода с прикрепленным демонстрационным кодом. Начальное количество лиц равно 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)

скриншот-1Не стирать (введенные пользователем) значения реактивных переменных при изменении входных значенийскриншот-2Не стирать (введенные пользователем) значения реактивных переменных при изменении входных значенийскриншот-3Не стирать (введенные пользователем) значения реактивных переменных при изменении входных значений

В среднем, сколько людей будет в приложении в любой момент времени?

jpdugo17 09.05.2022 01:08

В моем случае, я бы сказал, обычно менее 15 человек. @jpdugo17

OceanSky_U 09.05.2022 01:14

Простейшим случаем было бы инициализировать приложение с входными данными для 15 человек, но отображать или скрывать их по запросу пользователя. Другой альтернативой является использование функции insertUI. Какое решение вы предпочитаете?

jpdugo17 09.05.2022 01:17

Спасибо. @jpdugo17. Первый вариант не подходит для моего случая. Что касается insertUI, я только что проверил, и мне кажется, что он добавит независимый объект пользовательского интерфейса. В моем приложении мне понадобятся реактивные переменные, созданные на сервере (например, numericInput(paste0("age", i), label = "", value = 0)) для последующего использования. Будет ли работать этот insertUI? Кроме того, я заметил, что в некоторых сообщениях вставка UI сочетается с модулями, будет ли это работать в моем случае? Спасибо за помощь.

OceanSky_U 09.05.2022 01:38
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Редактировать:

Мы можем использовать 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 09.05.2022 17:14

@OceanSky_U Пожалуйста, посмотрите мое редактирование, теперь вы можете выбрать количество людей из числового ввода, как и раньше.

jpdugo17 15.05.2022 20:11

Замечательно! Кажется, «изолировать» — это именно то, что я ищу. Спасибо! @jpdugo17

OceanSky_U 16.05.2022 00:33

Другие вопросы по теме