Как один изолирует вход от другого входа в том же самом вызове блестящему :: renderUI? - PullRequest
0 голосов
/ 29 августа 2018

У меня есть несколько входов, которые существуют в одном и том же conditionalPanel, который создан на стороне сервера вещей с использованием renderUI. Я не могу переместить это в пользовательский интерфейс, потому что некоторые части используют реактивные объекты.

Я пытаюсь сделать так, чтобы один вход определял, каким должен быть ввод по умолчанию для другого входа. Однако, поскольку оба они существуют в одном и том же вызове renderUI, он создает циклическую зависимость, которая не позволяет мне выбирать что-либо, кроме опции по умолчанию для первого ввода. Рассмотрим этот пример app.R file:

library(shiny)

key <- c("a" = 1, "b" = 2, "c" = 3, "d" = 4)

ui <- fluidPage(
    uiOutput("inputs")
)

server <- function(input, output) {
  output$inputs <- renderUI(
    tagList(
      selectInput("input1", "Input 1:", letters[1:4]),
      textInput("input2", "Input 2:", rval())
    )
  )

  rval <- reactive(key[input$input1])

}

shinyApp(ui = ui, server = server)

Я определяю key в глобальной среде (в приложении это читается из файла .yaml в глобальной), затем uiOutput показывает пользователю все входные данные. Мы видим, что значение по умолчанию для input2 зависит от того, что выбрано для input1. В результате input1 вызывает изменение rval(), что, в свою очередь, вызывает изменение input2. Хорошо. Однако, поскольку input1 и input2 отображаются в одном и том же вызове renderUI, тогда input1 становится зависимым от самого себя, таким образом сбрасывая значение по умолчанию, когда пользователь выбирает другой параметр в раскрывающемся списке.

Опять же, я кодирую это так, потому что два входа существуют в одном и том же conditionalPanel в реальном приложении, с которым я работаю (хотя это не в этом рабочем примере).

Я пытался окружить selectInput(...) с isolate(), но это не работает.

Как я могу сохранить два входа в одном и том же renderUI, но разрешить пользователю изменять input1 без его зависимости от себя и сброса?

1 Ответ

0 голосов
/ 29 августа 2018

Вы можете использовать observeEvent(iunputs$input1, ...) и updateTextinput, чтобы поддерживать input2 в актуальном состоянии. Преимущество такого подхода заключается в том, что ваш пользовательский интерфейс не нужно перерисовывать так часто.

library(shiny)

key <- c("a" = 1, "b" = 2, "c" = 3, "d" = 4)

ui <- fluidPage(
  uiOutput("inputs")
)

server <- function(input, output, session) {
  output$inputs <- renderUI({
    tagList(
      selectInput("input1", "Input 1:", letters[1:4]),
      textInput("input2", "Input 2:", "placeholder")
    )
  })

  observeEvent(input$input1, {
    mapped_input <- key[[req(input$input1)]]
    updateTextInput(session, "input2", value = mapped_input)
  })

}

shinyApp(ui = ui, server = server)

req гарантирует, что updateTextInput будет вызван, только если output$inputs уже отрендерено.

Я понимаю, что есть случаи, когда функций updateXXX недостаточно для рендеринга динамических входов. В этом случае, вероятно, лучше всего генерировать пользовательские интерфейсы в отдельных операторах renderUI, чтобы цикличность больше не возникала.

Примечание: я не понимаю, как conditionalPanel делает необходимым использование renderUI. Если вы ищете способы использовать абстракцию в своем коде, используйте Shiny Modules .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...