如何在Crosstalk Shiny输入初始化时运行JavaScript设置筛选器默认值?
如何在Crosstalk Shiny输入初始化时运行JavaScript设置筛选器默认值?
我最近遇到个头疼的问题:想给Gender筛选器设置默认值为ALL,用的是crosstalk的filter_select()创建筛选器。点击「Run Report」按钮后,共享数据会生成、筛选器也能渲染出来,数据表格加载正常,筛选功能也没问题,但就是默认值死活不生效。我试着用JavaScript来解决,但好像没起到作用,下面是我最开始的代码:
library(shiny) library(DT) library(crosstalk) library(bslib) library(shinyjs) # Sample data for demonstration dat <- structure(list(`Disease-name` = c(4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L, 4002L), grp = c("TD", "PD", "ND", "ND", "PD", "ND", "PD", "PD", "ND", "TD", "TD", "TD", "TD", "ND", "ND", "ND", "PD", "ND", "PD", "ND", "PD", "ND", "PD", "TD", "TD", "TD", "TD", "PD", "PD", "PD", "ND", "ND", "PD", "TD", "TD", "TD" ), Gender = c("ALL", "MALE", "MALE", "MALE", "MALE", "MALE", "MALE", "MALE", "MALE", "MALE", "MALE", "MALE", "MALE", "ALL", "ALL", "FEMALE", "FEMALE", "FEMALE", "FEMALE", "FEMALE", "FEMALE", "FEMALE", "FEMALE", "FEMALE", "FEMALE", "FEMALE", "FEMALE", "ALL", "ALL", "ALL", "ALL", "ALL", "ALL", "ALL", "ALL", "ALL"), u_numpat = c(8L, 5L, 0L, 6L, 46L, 54L, 206L, 257L, 60L, 5L, 52L, 260L, 317L, 2L, 12L, 6L, 55L, 66L, 304L, 2L, 1L, 74L, 360L, 61L, 370L, 3L, 434L, 6L, 617L, 510L, 134L, 120L, 101L, 630L, 113L, 751L), w_numpat = c(179.82524660264, 105.148541663513, 0, 258, 1686.50661547721, 847, 3077.00035384634, 4868.65551098707, 1105, 105.148541663513, 1944.50661547721, 3924.00035384634, 5973.65551098707, 53, 527, 269, 2229.29975337235, 1105, 4389.38128191602, 53, 21.676704939127, 1427, 6640.3577402275, 2498.29975337235, 5494.38128191602, 74.676704939127, 8067.3577402275, 126.82524660264, 11509.0132512146, 7466.38163576236, 2532, 1952, 3915.80636884956, 9418.38163576236, 4442.80636884956, 14041.0132512146), `Age-Group` = c("under 18", "under 18", "under 18", "65 and over", "65 and over", "18 to 64", "18 to 64", "ALL", "ALL", "under 18", "65 and over", "18 to 64", "ALL", "under 18", "65 and over", "65 and over", "65 and over", "18 to 64", "18 to 64", "under 18", "under 18", "ALL", "ALL", "65 and over", "18 to 64", "under 18", "ALL", "under 18", "ALL", "18 to 64", "ALL", "18 to 64", "65 and over", "18 to 64", "65 and over", "ALL")), row.names = c(NA, 36L), class = "data.frame") ui <- page_navbar( tags$head( shinyjs::useShinyjs(), # 最开始的JS代码,页面加载完就执行,这时候筛选器还没生成 tags$script(HTML(" $(document).ready(function() { $('#filter_gender').find('.selectized').selectize()[0].selectize.setValue('ALL', false); }); ")) ), navbarMenu("Batch Cohort Analysis", icon = icon('ranking-star'), tabPanel("Cohort Selection", layout_sidebar( fillable = TRUE, fill = TRUE, full_screen = TRUE, sidebar = sidebar( width = 500, id = 'sidebar', bg = 'white', accordion( id = "myAccordion", accordion_panel( title = "User Inputs", icon = bsicons::bs_icon('menu-app'), actionButton(inputId = "run_report", label = "Run Report"), uiOutput("filtera") ) ) ), mainPanel( width = 12, div(id='headingtxt', "Main Content Area"), DTOutput("report_table") ) ) ) ) ) server <- function(input, output, session) { observeEvent(input$run_report, { shared_data <- SharedData$new(dat) output$filtera <- renderUI({ tagList( h4("Filters"), fluidRow( # 最开始这里没补全filter_select的完整代码 column(3, filter_select( inputId = "filter_gender", label = "Gender", sharedData = shared_data, group = ~Gender )) ) ) }) output$report_table <- renderDT({ datatable(shared_data) }) }) } shinyApp(ui, server)
问题根源
最开始的问题出在JavaScript执行时机不对:$(document).ready()是页面加载完成就执行,但筛选器是点击Run Report后才动态渲染出来的,这时候JS代码执行时,筛选器元素根本还不存在,自然找不到元素设置不了默认值。
修复方案
我们需要确保JS代码在筛选器完全生成并初始化后再执行,这里有两种简单的实现方式:
方式1:把JS代码嵌入renderUI中
直接在生成筛选器的renderUI里添加JS代码,再用setTimeout稍微延迟一下(给selectize组件留一点初始化时间):
output$filtera <- renderUI({ tagList( h4("Filters"), fluidRow( column(3, filter_select( inputId = "filter_gender", label = "Gender", sharedData = shared_data, group = ~Gender )) ), # 筛选器生成后延迟执行JS设置默认值 tags$script(HTML(" setTimeout(function() { const selectizeEl = $('#filter_gender').find('.selectized')[0]?.selectize; if(selectizeEl) { selectizeEl.setValue('ALL', false); } }, 100); ")) ) })
方式2:用shinyjs的runjs延迟执行
在observeEvent里,筛选器和表格渲染完成后,调用shinyjs::runjs:
observeEvent(input$run_report, { shared_data <- SharedData$new(dat) output$filtera <- renderUI({ tagList( h4("Filters"), fluidRow( column(3, filter_select( inputId = "filter_gender", label = "Gender", sharedData = shared_data, group = ~Gender )) ) ) }) output$report_table <- renderDT({ datatable(shared_data) }) # 延迟运行JS设置默认值 shinyjs::delay(100, { shinyjs::runjs(" const selectizeEl = $('#filter_gender').find('.selectized')[0]?.selectize; if(selectizeEl) { selectizeEl.setValue('ALL', false); } ") }) })
最终效果
修改后,点击Run Report按钮,Gender筛选器会自动选中ALL,完全符合预期。
备注:内容来源于stack exchange,提问作者sutsabs
相关产品推荐
相关产品推荐

