insertUI для создания бесконечного ввода на основе предыдущего значения

Вопрос или проблема

Я пытаюсь использовать либо insertUI, либо renderUI, чтобы создать бесконечные потенциальные поля ввода для пользователя. Насколько я понимаю, это легко достигается с помощью actionButton, вот пример использования actionButton: использование actionButton + insertUI в модулях R shiny для создания нескольких вводов. Однако я не видел использования в открытых полях ввода, таких как текстовые или числовые. Когда я пытаюсь создать экземпляры на основе текстового/числового ввода, похоже, я всегда создаю дубликаты с помощью insertUI или renderUI.

  • Мой код будет использовать модуль для UI для создания numericInput.
  • Затем я использую второй модуль для сервера, чтобы создать observeEvent, который проверяет число во входных данных. Если число существует и больше 10, то он использует insertUI с использованием модуля UI.
  • В сервере я использую observe, чтобы проверить количество вводов, чтобы он знал, сколько серверных модулей создать. Здесь, я подозреваю, может быть проблема, так как это, похоже, создает несколько экземпляров модуля UI. Мне уже говорили, что это плохая практика иметь observeEvent внутри observe, хотя я не уверен, как иначе это осуществить.

Как я могу вставить только один UI, а не несколько UI?

Код:

library(shiny)

#Модули и функции########################
#Модуль UI для создания числового ввода
numericModule <- function(id) { 
  numericInput(inputId = NS(id, "Numeric"), 
               label = paste0(id), 
               value = NA)  
}

#Это мой серверный модуль. Если число больше 10, вставить UI
numericObserver <- function(id) {

  moduleServer(id, function(input, output, session) {
    #Для числового ввода, наблюдение события
    observeEvent(input$Numeric, {

      #Если значение существует и больше 10...
      if(!any(is.null(input$Numeric),
             is.na(input$Numeric),
             input$Numeric < 10)) {

        #Вставьте новый ввод после
        insertUI(selector = paste0("#", NS(id, "Numeric")),
                 where = "afterEnd",
                 ui = numericModule(id+1))

      }
    })

  })
}

#UI ########################

ui <- fluidPage(
  numericModule(1)
)

#СЕРВЕР ##########################

server <- function(input, output, session) {

  #Наблюдайте за вводами. Для каждого ввода создавайте новый серверный модуль
  #*Здесь я считаю, что может быть проблема***
  observe({

    lapply(1:length(names(input)), function(x) {

      numericObserver(x)

    })

  })

}

#ЗАПУСК SHINY#################
shinyApp(ui, server)

Ответ или решение

Чтобы создать систему, позволяющую динамически добавлять numericInput в R Shiny, можно использовать функции insertUI и observeEvent для создания новых полей ввода на основе предыдущих значений. Ниже приведено решение вашей проблемы, обеспечивающее добавление новых полей ввода только при выполнении определенных условий, избегая дублирования.

Перепишите ваш код, как показано ниже:

library(shiny)

# Модуль UI для создания числового ввода
numericModule <- function(id) { 
  numericInput(inputId = NS(id, "Numeric"), 
               label = paste("Числовой ввод", id), 
               value = NA)  
}

# Модуль сервера, который наблюдает за вводом
numericObserver <- function(id) {

  moduleServer(id, function(input, output, session) {
    # Наблюдение за введенным значением
    observeEvent(input$Numeric, {

      # Если значение существует и больше 10, добавляем новый ввод
      if (!is.null(input$Numeric) && !is.na(input$Numeric) && input$Numeric > 10) {

        # Проверяем, существует ли уже новый ввод с этим идентификатором
        if (!isTRUE(NS(id, "Numeric") %in% input)) {
          # Вставляем новый ввод
          insertUI(selector = paste0("#", session$ns("Numeric")),
                   where = "afterEnd",
                   ui = numericModule(as.numeric(id) + 1))
        }
      }
    })

  })
}

# UI
ui <- fluidPage(
  numericModule(1) # Инициализируем первый ввод
)

# SERVER
server <- function(input, output, session) {

  # Наблюдаем за числовыми вводами, чтобы создать серверный модуль для каждого
  observe({
    # Используем lapply для создания наблюдателей для каждого ввода
    input_ids <- unique(as.numeric(sub("Numeric_", "", names(input))))
    lapply(input_ids, function(x) {
      numericObserver(x)
    })
  })

}

# Запускаем приложение Shiny
shinyApp(ui, server)

Объяснение изменений:

  1. Уникальные идентификаторы: Вместо того чтобы просто использовать идентификаторы на основе очередности, убедитесь, что они уникальны, используя NS для участия и избегания конфликтов имен.

  2. Проверка существования ввода: Перед добавлением нового ввода мы проверяем, существует ли уже новый input с тем же идентификатором, чтобы предотвратить дублирование.

  3. Обработка идентификаторов: Используем sub и unique, чтобы извлекать идентификаторы инпутов, что позволяет нам избегать дублирования одних и тех же идентификаторов при добавлении новых инпутов.

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

Оцените материал
Добавить комментарий

Капча загружается...