I want to add tool tips to an dynamic user interface. When I initialize the UI the tool tips are working fine
selectInput(ns("Main2_1"),"Label","abc", selectize = TRUE, multiple = TRUE),
bsPopover(ns("Main2_1"), "Label", "content", placement = "left", trigger = "focus"),
but once I use to update the choices of Main2_1
in my server script with
updateSelectInput(session, "Main2_1", choices=foo)
it deletes the tool tip too. Adding a new tool tip with addPopover
on the server side does not eliminates the problem
I agree, this is some poor design right there. I can't even tell, why the addPopover
won't work. Maybe because the observers don't execute the commands one by one...
However, there is a way to get to your thing. By rewriting the bsPopover
, we can take changes of the corresponding element into account.
I created an updateResistantPopover
function, that adds an additional eventListener (mutationListener) to the element, whos id is given, that re-installs the popover whenever some child of the element changes.
Example code below:
library(shiny)
library(shinyBS)
updateResistantPopover <- function(id, title, content, placement = "bottom", trigger = "hover", options = NULL){
options = shinyBS:::buildTooltipOrPopoverOptionsList(title, placement, trigger, options, content)
options = paste0("{'", paste(names(options), options, sep = "': '", collapse = "', '"), "'}")
bsTag <- shiny::tags$script(shiny::HTML(paste0("
$(document).ready(function() {
var target = document.querySelector('#", id, "');
var observer = new MutationObserver(function(mutations) {
setTimeout(function() {
shinyBS.addTooltip('", id, "', 'popover', ", options, ");
}, 200);
});
observer.observe(target, { childList: true });
});
")))
htmltools::attachDependencies(bsTag, shinyBS:::shinyBSDep)
}
ui <- shinyUI(fluidPage(
selectInput("Main2_1","Label","abc", selectize = TRUE, multiple = TRUE),
updateResistantPopover("Main2_1", "Label", "content", placement = "right", trigger = "focus"),
actionButton("destroy", "destroy!")
))
server <- function(input, output, session){
observeEvent(input$destroy, {
updateSelectInput(session, "Main2_1", choices="foo")
})
}
shinyApp(ui, server)