Как наблюдать и отслеживать одно значение из двух элементов renderUI в блестящем - PullRequest
1 голос
/ 25 марта 2019

Вот простое приложение, в котором пользователь может либо ввести (numericInput, bpm_numeric), либо вставить (sliderInput, bpm_slider) входное значение. Оба эти элемента пользовательского интерфейса должны синхронизироваться с любым из них. Однако вывод нужно отслеживать только один раз. Ниже я отслеживаю его дважды, но мне нужна только одна копия «выбора / ввода» от пользователя. Я думаю, что мне нужно использовать reactiveValues, но я не уверен в подходе.

library(shiny)

ui <- fluidPage(

    titlePanel("Reverb & Delay Calculator"),

    sidebarLayout(
        sidebarPanel(
            uiOutput("bpm_numeric"),
            uiOutput("bpm_slider")
        ),
        mainPanel(
            p("Numeric value is:"),
            verbatimTextOutput("numeric_val"),
            p("Slider value is:"),
            verbatimTextOutput("slider_val")
        )
    )
)

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

    output$bpm_numeric = renderUI({
        numericInput(
            "bpm_numeric",
            "BPM Numeric",
            value = 60, min = 40, max = 300
        )
    })

    output$bpm_slider = renderUI({
        sliderInput(
            "bpm_slider",
            "BPM Slider",
            value = 60, min = 40, max = 300
        )
    })

    # See how I can track "both", but really I only need to track "one" since
    # they should stay in-sync with one another. Maybe reactiveValues???
    output$numeric_val <- renderText({ input$bpm_numeric })
    output$slider_val <- renderText({ input$bpm_slider })

    observeEvent(input$bpm_numeric, {
        val = input$bpm_numeric
        updateSliderInput(session, "bpm_slider", value = val)
    })

    observeEvent(input$bpm_slider, {
        val = input$bpm_slider
        updateNumericInput(session, "bpm_numeric", value = val)
    })

}

shinyApp(ui = ui, server = server)

Shiny App

ПРИМЕЧАНИЕ. Хотя в настоящее время я использую uiOuput() + renderUI() + update___Input(), это необязательно. Я открыт для других подходов, при условии, что входной интерфейс остается в синхронизации У меня есть одна копия синхронизированного вывода.

1 Ответ

1 голос
/ 25 марта 2019

Вот мысль. Он может обобщать немного , но все равно полагается на то, что вы прекрасно знаете, какие идентификаторы вы хотите объединить таким образом.

Моды к вашему текущему примеру:

  1. Определите глобальный defbmp <- 60, полезно, чтобы убедиться, что все элементы начинаются в одном месте.
  2. За исключением нового useval реактива, замените все ссылки на input$bpm_numeric или _slider на useval().
  3. Полезно для отслеживания состояния, добавить lastval реактивное значение.
  4. Наконец, блок useval <- eventReactive({},{}), в зависимости от каждого из элементов, подлежащих синхронизации.

Конечный продукт (за исключением компонента ui, там без изменений):

defbpm <- 60                                       # new

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

    output$bpm_numeric = renderUI({
        numericInput(
            "bpm_numeric",
            "BPM Numeric",
            value = defbpm, min = 40, max = 300    # update
        )
    })

    output$bpm_slider = renderUI({
        sliderInput(
            "bpm_slider",
            "BPM Slider",
            value = defbpm, min = 40, max = 300    # update
        )
    })

    output$numeric_val <- renderText({ useval() }) # update
    output$slider_val <- renderText({ useval() })  # update

    lastval <- shiny::reactiveVal(defbpm)          # new
    useval <- eventReactive({
      input$bpm_numeric
      input$bpm_slider
    }, {
      newval <- setdiff(c(input$bpm_numeric, input$bpm_slider), lastval())
      if (length(newval) > 0) {
        if (newval != input$bpm_numeric) updateNumericInput(session, "bpm_numeric", value = newval)
        if (newval != input$bpm_slider) updateSliderInput(session, "bpm_slider", value = newval)
        lastval(newval)
      }
      lastval()
    })                                             # new

}

Пути улучшения этого (пока не знаю):

  1. программно определяет элементы для синхронизации, такие как character вектор идентификаторов;
  2. обновление eventReactive, чтобы условное выражение генерировалось программно, я просто недостаточно гуру, чтобы делать это сейчас; и
  3. определяет во время выполнения, представляет ли данный идентификатор numericInput или sliderInput (или что-то еще), так что функции update* можно вызывать более обобщенно.
...