![](/img/trans.png)
[英]How to select a Span from a same-name group based on attribute (e.g. Class)
[英]Can you tell a MutationObserver to only listen to specific inputs, e.g. to select an entire group of choices in a pickerInput?
这是受启发和跟进Is there a way to select a whole group of selection on a pickerInput from shinyWidgets?
所选答案对于单个pickerInput
,但是一旦第二个(“稍后”)答案出现在同一个应用程序中,就会出现问题。 例如,考虑具有两个pickerInput
的设置:
library(shiny)
library(shinyWidgets)
js <- HTML("
$(function() {
let observer = new MutationObserver(callback);
function clickHandler(evt) {
Shiny.setInputValue('group_select', $(this).children('span').text(),{priority: \"event\"});
}
function callback(mutations) {
for (let mutation of mutations) {
if (mutation.type === 'childList') {
$('.dropdown-header').on('click', clickHandler).css('cursor', 'pointer');
}
}
}
let options = {
childList: true,
};
observer.observe($('.inner')[0], options);
})
")
choices <- list("A" = c(1, 2, 3, 4, 5), "B" = c(6, 7, 8, 9, 10), "C" = c(11,12,13,14,15))
ui <- fluidPage(
tags$head(tags$script(js)),
pickerInput("test", choices = choices, multiple = TRUE,options = list('actions-box' = TRUE)),
textOutput("testOutput"),
pickerInput("test_2", choices = choices, multiple = TRUE,options = list('actions-box' = TRUE)),
textOutput("testOutput_2")
)
server <- function(input, output, session) {
output$testOutput <- renderText({paste(input$test)})
output$testOutput_2 <- renderText({paste(input$test_2)})
observeEvent(input$group_select, {
req(input$group_select)
if(all(choices[[input$group_select]] %in% input$test_2)){
sel <- input$test_2[!(input$test_2 %in% choices[[input$group_select]])]
}else{
sel <- union(input$test_2, choices[[input$group_select]])
}
updatePickerInput(session, "test_2", selected = sel)
})
}
shinyApp(ui = ui, server = server)
这样,单击第一个pickerInput
中的组会更新第二个,而单击第二个中的组则不会执行任何操作。 如何告诉MutationObserver
在第二个pickerInput
中侦听并且仅侦听突变?
在我的实际用例中,我希望在两个不同的选项卡(来自shinydashboard
)上有两个不同的pickerInput
,我希望有这个功能。 所以也许告诉MutationObserver
在哪个选项卡上查看就足够了? (请参阅How do I use shinyjs to identify if tab is active in shiny? ,但作为 JS 初学者,我不确定如何使用它)。
更新
通过将req(input$sidebar == "tab_name")
添加到observeEvent
部分,我设法在我的用例中稍微接近了一点。 现在他们都更新了正确的pickerInput
,但是对于第二个,每次我点击第一个pickerInput
中的组 header 后,该功能只工作一次。
所以,还是没有。 我正在尝试使用来自shinydashboard
的选项卡来获得一个可重现的示例,但由于某种原因,一旦我将它们介绍给 MWE,整个mutationObserver
就会完全停止工作。
更新 2
@thothal 的回答有效。 我将observeEvent
部分重写为以下内容以获得相同的功能:
observeEvent(input$group_select, {
req(input$group_select)
if(all(choices[[input$group_select[[1]]]] %in% input[[names(input$group_select)]])){
sel <- input[[names(input$group_select)]][!(input[[names(input$group_select)]] %in% my_choices[[input$group_select[[1]]]])]
}else{
sel <- union(input[[names(input$group_select)]],my_choices[[input$group_select[[1]]]])
}
updatePickerInput(session,names(input$group_select),selected = sel)
})
原始答案的作者在这里。 实际上,您需要按如下方式调整代码:
clickHandler
应该返回单击的pickerInput
的 id,以便Shiny
可以知道要更新哪个pickerInput
。observer
必须在不同的节点上侦听。 class .inner
与fluidPage
布局配合得很好,因为显然.inner
class 在加载 DOM 时存在,但不与shinydashboard
一起使用(我猜当 JS 触发时这些部件尚未加载)。 最简单的是听body
(肯定会在那里),但这可能是一项昂贵的操作,b/ca 更窄的目标可能需要更少的资源。 话虽如此,一个可行的解决方案看起来像这样(注意您可以添加尽可能多的pickerInputs
,并且处理程序应该按预期工作):
library(shiny)
library(shinyWidgets)
library(shinydashboard)
library(purrr)
js <- HTML("
$(function() {
let observer = new MutationObserver(callback);
function clickHandler(evt) {
let id = $(this).parents('.bootstrap-select').children('select').attr('id');
let res = {};
res[id] = $(this).children('span').text();
Shiny.setInputValue('group_select', res);
}
function callback(mutations) {
for (let mutation of mutations) {
if (mutation.type === 'childList') {
$('.dropdown-header').on('click', clickHandler).css('cursor', 'pointer');
}
}
}
let options = {
childList: true,
};
observer.observe($('body')[0], options);
})
")
choices <- list("A" = c(1, 2, 3, 4, 5), "B" = c(6, 7, 8, 9, 10))
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(pickerInput("test1", choices = choices, multiple = TRUE),
pickerInput("test2", choices = choices, multiple = TRUE)),
dashboardBody(tags$head(tags$script(js)),
verbatimTextOutput("testOutput")),
title = "Multipicker"
)
server <- function(input, output, session) {
output$testOutput <- renderPrint({
input$group_select
})
observeEvent(input$group_select, {
req(input$group_select)
iwalk(input$group_select, ~ updatePickerInput(session, .y, selected = choices[[.x]]))
})
}
shinyApp(ui = ui, server = server)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.