ebailey78 / shinyBS

Twitter Bootstrap Components for Shiny
182 stars 47 forks source link

Tooltip bug? #21

Open jgabry opened 9 years ago

jgabry commented 9 years ago

Thanks for the great work!

I've noticed strange behavior with tooltips in the shinyBS3 branch and I can't quite figure out what's going on. I've tried to recreate the problem with a minimal example:

Below is the bsCollapse example you provide (copied verbatim) but with two added action buttons with tooltips. When I run this app only the "test2" tooltip renders. The only difference between the two is that one action button has been added via renderUI and the other directly in the ui.

app <- shinyApp(
  ui = 
    fluidPage(
      sidebarLayout(
        sidebarPanel(HTML("This button will open Panel 1 using <code>updateCollapse</code>."), 
                     actionButton("p1Button", "Push Me!"),
                     selectInput("styleSelect", "Select style for Panel 1", 
                                 c("default", "primary", "danger", "warning", "info", "success"))
        ),
        mainPanel(
          bsCollapse(id = "collapseExample", open = "Panel 2",
                     bsCollapsePanel("Panel 1", "This is a panel with just text ",
                                     "and has the default style. You can change the style in ",
                                     "the sidebar.", style = "info"),
                     bsCollapsePanel("Panel 2", "This panel has a generic plot. ",
                                     "and a 'success' style.", plotOutput("genericPlot"), style = "success")
          ),

          uiOutput("tooltip_test"),
          bsTooltip("test", title = "Test", placement="right"),
          actionButton("test2", "Test2"),
          bsTooltip("test2", title = "Test2", placement="right")
        )
      )
    ),
  server = 
    function(input, output, session) {
      output$genericPlot <- renderPlot(plot(rnorm(100)))  
      observeEvent(input$p1Button, ({
        updateCollapse(session, "collapseExample", open = "Panel 1")
      }))
      observeEvent(input$styleSelect, ({
        updateCollapse(session, "collapseExample", style = list("Panel 1" = input$styleSelect))
      }))

      output$tooltip_test <- renderUI({
        actionButton("test", "Test")
      })
    }
)

runApp(app)

What's also very strange is that if I remove the collapse panels (e.g. just have the actionButtons and tooltips in the mainPanel) then both tooltips work perfectly.

ebailey78 commented 9 years ago

Thank you for the feedback. That's interesting. It looks like its a timing issue. bsTooltip is firing before shiny has had the chance to render the button. shinyBS waits 100ms to give shiny a chance to load everything but apparently that isn't enough time in this case. When you remove the collapses, shiny renders the button sooner and its there when bsTooltip fires. I increased the delay from 100ms to 500ms and that seems to be enough time to render the button with or without the collapses.

I think the better way to handle this may be to include bsTooltip as part of renderUI so in your server script you would have something like this:

  output$tooltip_test <- renderUI({
    tagList(
        actionButton("test", "Test"),
        bsTooltip("test", title = "Test", placement="right")
    )
  })

I tested that and it seems to work in your example. Let me know if it fixes the real problem you are having. Regardless, there should be a more intuitive way to add tooltips and popovers to rendered elements. I will see what I can do.

Thanks,

Eric

jgabry commented 9 years ago

Thanks! The increase from 100ms to 500ms definitely seems to help.

ebailey78 commented 9 years ago

I just added a new function tipify so you can wrap any other shiny element in tipify and it will create a tooltip on the wrapped element. I think this is a better solution than hoping that the timing works out right. So instead of bsTooltip in your UI, your server would look like this:

output$tooltip_test <- renderUI({
    tipify(actionButton("test", "Test"), title = "Test", placement = "right")
})

If you can, try it and see if it works for you. I think this would be a safer method for adding tooltips to elements created with renderUI.

jgabry commented 9 years ago

Cool. That seems like a good idea. It does work for me in the toy example, but I can't get it to work in my actual shiny app. Here's the relevant code from my server and ui files:

In server.R

output$ui_multiview_customize <- renderUI({
  bsCollapse(
    bsCollapsePanel(title = "View Options",
      checkboxInput("multiview_checkbox", label = "Include warmup", value = FALSE),
      hr(),
      tipify(downloadButton("download_multiview", "Save as ggplot2 objects"), 
         title = "Save ggplot2 object in .RData file.", placement="right")
    )
  )
})

and then in ui.R I have

tabPanel("Multiview", 
   uiOutput("ui_multiview_customize"),
   plotOutput("multiview_plot")
)

Everything works fine except the tooltip doesn't show up.

ebailey78 commented 9 years ago

I created this example to try to replicate your situation:

library(shiny)
library(shinyBS)

shinyApp(
  ui =
    fluidPage(
      tabsetPanel(
        tabPanel("Tab #1",
          plotOutput("genericPlot")
        ),
        tabPanel("Tab #2",
          uiOutput("ui_multiview_customize"),
          plotOutput("multiview_plot")
        )
      )
    ),  
  server =
    function(input, output, session) {
      output$genericPlot <- renderPlot(plot(rnorm(1000)))
      output$multiview_plot <- renderPlot(plot(runif(1000)))
      output$ui_multiview_customize <- renderUI({
        bsCollapse(
          bsCollapsePanel(title = "View Options",
                          checkboxInput("multiview_checkbox", label = "Include warmup", value = FALSE),
                          hr(),
                          tipify(downloadButton("download_multiview", "Save as ggplot2 objects"), 
                                 title = "Save ggplot2 object in .RData file.", placement="right")
          )
        )
      })
    }
)

And tipify works for me in this example. Am I missing something?

jgabry commented 9 years ago

Hmmm, tipify works for me too in this example, so I don't think you're missing anything.

It just doesn't work when this example is placed in the larger context of my app. There must be something else going on in my app that prevents it from working, but I'm not sure what it would be.

stevepowell99 commented 8 years ago

aha, do these delay issues affect bsCollapse as well? I have an app in which the panels keep closing as soon as they have fully opened, I think because the app is taking rather long render its stuff. If so, is there an easy way to tweak the delay, I can't find it in the code.