【问题标题】:Prevent pickerInput from updating every time something is selected (R, Shiny)每次选择某些内容时防止 pickerInput 更新(R,Shiny)
【发布时间】:2021-10-21 00:37:42
【问题描述】:

我已经搜索了 stackoverflow 和完整的网络,但对于这个看似简单的问题,我似乎找不到一个好的答案。

情况如下:

  • 我有一个 Shiny 应用程序,与数据库连接
  • 我有几个用户输入 (Pickerinputs),用户可以在其中选择多个参数
  • 用户输入都相互依赖

出现的问题如下:

  • 如果用户勾选了多个汽车品牌(例如,雷诺、标致和宝马),则与此选择相关联的选择器输入(这些品牌的特定汽车型号)会更新 3 次。由于许多选择器输入相互链接,这会造成混乱的用户体验。

解决方案需要

  • 我觉得解决方法很简单:pickerinput只需要在input关闭后发送选择的值即可;它不需要在用户每次选择后发送值(并触发更新)。 Shinywidgets 的AirdatePickerInput 具有此特定功能(update_on=c('change', 'close')。我需要的是我的 pickerInput 在“关闭”时更新。因此结果值仅发送回服务器一次.

示例: 界面

ui <- fluidPage(
  
  # Title panel
  fluidRow(
    column(2,
           wellPanel(
           h3("Filters"),
           uiOutput("picker_a"),
           uiOutput("picker_b"),
           )
    ),
  )
)

服务器

server <- function(input, output, session) {
  
  # Start values for each filter  
  all_values_for_a <- tbl(conn, "table") %>%
    distinct(a) %>%
    collect()
  
  all_values_for_b <- tbl(conn, "table") %>%
    distinct(b) %>%
    collect()
  
  output$picker_a <- renderUI({
    pickerInput(
      inputId = "picker_a",
      label = "a:", 
      choices = all_values_for_a,
      selected = all_values_for_a,
      multiple = TRUE,
      options = list("live-search" = TRUE, "actions-box" = TRUE))
  })
  
  output$picker_b <- renderUI({
    pickerInput(
      inputId = "picker_b",
      label = "b:", 
      choices = all_values_for_b,
      selected = all_values_for_b,
      multiple = TRUE,
      options = list("live-search" = TRUE, "actions-box" = TRUE))
  })
  
  #I want this code to be executed ONLY when
  #picker_a is closed, not everytime when the user
  #picks an item in picker_a
  observeEvent(
    input$picker_a,
    {
      all_values_for_b <- tbl(conn, "table") %>%
        filter(a %in% !!input$picker_a) %>%
        distinct(b) %>%
        collect()
      updatePickerInput(session, "picker_b", choices = all_values_for_b, selected = all_values_for_b)
    })
    )
  )
}

【问题讨论】:

标签: javascript r shiny


【解决方案1】:

一旦用户选择了所有值,您可能可以使用actionButton 来延迟更新的执行。

或使用debounce 函数,请参阅this other post

编辑

update_on = c("change", "close") 功能被要求向 shinyWidgets 开发人员 (Victor Perrier) on GitHub 提供 pickerInput 小部件。

维克多的回答是:

pickerInput 没有类似的参数,但是有一个特殊的输入可以知道菜单是否打开。所以你可以使用一个中间的 reactiveValue 来达到同样的效果。

他提供了以下代码:

library(shiny)
library(shinyWidgets)

ui <- fluidPage(
  fluidRow(
    column(
      width = 4,
      pickerInput(
        inputId = "ID",
        label = "Select:",
        choices = month.name,
        multiple = TRUE
      )
    ),
    column(
      width = 4,
      "Immediate:",
      verbatimTextOutput("value1"),
      "Updated after close:",
      verbatimTextOutput("value2")
    ),
    column(
      width = 4,
      "Is picker open ?",
      verbatimTextOutput("state")
    )
  )
)

server <- function(input, output) {
  
  output$value1 <- renderPrint(input$ID)
  output$value2 <- renderPrint(rv$ID_delayed)
  output$state <- renderPrint(input$ID_open)
  
  rv <- reactiveValues()
  observeEvent(input$ID_open, {
    if (!isTRUE(input$ID_open)) {
      rv$ID_delayed <- input$ID
    }
  })
}

shinyApp(ui, server)

你可以试试:

  observeEvent(
    input$picker_a_open,
    {
    if (!isTRUE(input$picker_a_open)) {
      all_values_for_b <- tbl(conn, "table") %>%
        filter(a %in% !!input$picker_a) %>%
        distinct(b) %>%
        collect()
      updatePickerInput(session, "picker_b", choices = all_values_for_b, selected = all_values_for_b)
}
    })

【讨论】:

  • 感谢您的回答。我已经想到了一个 Actionbutton,但这似乎不是目前最直观的选择。尽管这可能有效,但这是用户每次都需要执行的额外操作。我宁愿选择一个不会为用户带来额外操作的选项。 debounce 函数似乎是一个不错的选择。我仍在寻找 PickerInput 端的 change = on_close 选项...
  • shinyWidgets' GitHub 上找到完全相同的请求,请参阅我的更新答案
  • 这个更新的答案是完美的,完全符合我的需要。非常感谢!
猜你喜欢
  • 2018-11-09
  • 2019-02-04
  • 2019-02-12
  • 1970-01-01
  • 2020-08-20
  • 1970-01-01
  • 1970-01-01
  • 2019-12-26
  • 1970-01-01
相关资源
最近更新 更多