如何为shinyWidgets的selectizeGroupUI实现输入值书签保存功能
问题描述
开发R Shiny应用时,使用shinyWidgets包的selectizeGroupUI组件构建多维度用户筛选输入控件,启用Shiny书签功能保存应用状态时,该组件的用户选中值无法被正常存储,原有实现无法完成selectizeGroupUI的状态书签保存,可复现问题的示例代码如下:
library(shiny) library(shinyWidgets) data("mpg", package = "ggplot2") ui <- function(request) { fluidPage( fluidRow( column( width = 10, offset = 1, bookmarkButton(), tags$h3("Filter data with selectize group"), panel( selectizeGroupUI( id = "my-filters", params = list( manufacturer = list(inputId = "manufacturer", title = "Manufacturer:"), model = list(inputId = "model", title = "Model:"), trans = list(inputId = "trans", title = "Trans:"), class = list(inputId = "class", title = "Class:") ) ), status = "primary"), DT::dataTableOutput(outputId = "table")))) } server <- function(input, output, session) { vals <- reactiveValues(sum = NULL) res_mod <- callModule( module = selectizeGroupServer, id = "my-filters", data = mpg, vars = c("manufacturer", "model", "trans", "class")) output$table <- DT::renderDataTable(res_mod()) # 原有书签逻辑无法保存筛选值 onBookmark(function(state) { state$values$filtered <- res_mod() }) onRestore(function(state) { vals$sum <- state$values$filtered }) } shinyApp(ui, server, enableBookmarking = "server")
问题原因
selectizeGroupUI/selectizeGroupServer是shinyWidgets封装的模块组件,筛选值的联动逻辑全部在模块内部维护,不会自动被Shiny默认的书签采集逻辑捕获;原有代码仅存储了过滤后的最终数据集,没有存储每个筛选项的选中值,也没有在书签恢复时触发组件的回填更新逻辑,因此无法还原筛选状态。
解决方案
核心处理逻辑分两步:
- 保存书签时,主动提取带模块命名空间的所有筛选框的实时选中值,存入书签字段
- 恢复书签时,等待组件初始化完成后,逐一把保存的选中值回填到对应筛选输入框,触发组件自带的联动筛选逻辑,自动还原过滤结果
修改后的可直接运行的代码如下:
library(shiny) library(shinyWidgets) data("mpg", package = "ggplot2") ui <- function(request) { fluidPage( fluidRow( column( width = 10, offset = 1, bookmarkButton(), tags$h3("Filter data with selectize group"), panel( selectizeGroupUI( id = "my-filters", params = list( manufacturer = list(inputId = "manufacturer", title = "Manufacturer:"), model = list(inputId = "model", title = "Model:"), trans = list(inputId = "trans", title = "Trans:"), class = list(inputId = "class", title = "Class:") ) ), status = "primary"), DT::dataTableOutput(outputId = "table")))) } server <- function(input, output, session) { res_mod <- callModule( module = selectizeGroupServer, id = "my-filters", data = mpg, vars = c("manufacturer", "model", "trans", "class") ) output$table <- DT::renderDataTable(res_mod()) # 保存书签时存储所有筛选项的选中值 onBookmark(function(state) { # 模块命名空间为my-filters,内部输入ID格式为 模块ID-输入ID state$values$sel_manufacturer <- input[["my-filters-manufacturer"]] state$values$sel_model <- input[["my-filters-model"]] state$values$sel_trans <- input[["my-filters-trans"]] state$values$sel_class <- input[["my-filters-class"]] }) # 恢复书签时回填选中值,onRestored会在应用初始状态加载完成后触发 onRestored(function(state) { updateSelectizeInput( session, inputId = "my-filters-manufacturer", selected = state$values$sel_manufacturer ) updateSelectizeInput( session, inputId = "my-filters-model", selected = state$values$sel_model ) updateSelectizeInput( session, inputId = "my-filters-trans", selected = state$values$sel_trans ) updateSelectizeInput( session, inputId = "my-filters-class", selected = state$values$sel_class ) }) } shinyApp(ui, server, enableBookmarking = "server")
注意:如果筛选维度更多,按相同规则追加对应输入值的存取逻辑即可,回填后组件会自动触发级联过滤,不需要手动处理过滤后的数据。
内容的提问来源于stack exchange,提问作者samir
相关产品推荐
相关产品推荐

