Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timers aren't connected to JS scripts when generated programatically in Shiny #59

Open
petersmp opened this issue Mar 29, 2024 · 1 comment
Assignees
Labels
priority: high High priority status: planned Planning to implement type: new New feature or enhancement

Comments

@petersmp
Copy link

petersmp commented Mar 29, 2024

I am trying to write a Shiny app that allows users to create multiple timers with labels (and some other controls). The plan is to allow them to create an arbitrary number of timers, so I was trying to use renderUI to generate the timers. They render correctly, but they do not respond to controls. Looking at the inspect tools in the browser, it appears that this is because the newly created timers are not registered with the correct triggers for the javascript controls.

If I load a timer using the hidden function from shinyjs, it loads correctly. I am going to try this work around, but it makes the controls a fair bit more cumbersome.

If someone can point me to where the triggers are registered, I would be happy to take a stab at a fix here. I just haven't done enough in that area to track down the code that I need to dig into.

Reproducible example:

library(shiny)
library(countdown)
library(shinyjs)

demo_app <- shinyApp(
  ui = fluidPage(
    textInput(
      "timer_labels"
      , "Labels for timers (separate with commas)"
      , "Timer 1, Timer 2, Timer 3"
      , width = "100%"
    )
    , actionButton("create_label_timers"
                   , "Create timers for each label")
    
    , uiOutput("timer_holder")
    
    , div(
      h3("This one loads automatically")
      , countdown(
        id = "countdown_auto"
        , class = "inline"
      )
    )
    
    
    , useShinyjs()
    , h3("This one is hidden to start")
    , actionButton("show", "Show")
    , hidden(
      countdown(
        id = "countdown_hidden"
        , class = "inline"
      )
    )
  )
  
  , server = function(input, output){
    output$timer_holder <- renderUI({
      
      if(input$create_label_timers == 0){
        return(p("Click a button above to generate timers")) 
      }
      
      if(input$timer_labels == ""){
        return(p("Please enter labels to use the label method"))
      }
      
      in_labels <-
        strsplit(input$timer_labels, ",")[[1]]
      
      
      timer_list <- tagList(lapply(1:length(in_labels), function(this_label_n){
        div(
          h3(in_labels[this_label_n])
          , countdown(
            id = paste0("countdown_timer_"
                        , this_label_n)
            , class = "inline"
          )
        )
      }))
      
      return(timer_list)
      
      
    })
    
    observeEvent(input$show, {
      show("countdown_hidden")
    })
    
    
    
  }
  
)


runApp(demo_app)
@gadenbuie
Copy link
Owner

Thanks for the report! It makes sense that dynamically-created timers aren't working in Shiny: the timers are only initialized when the page is loaded

countdown/lib/countdown.js

Lines 439 to 446 in c810f16

document.addEventListener('DOMContentLoaded', function () {
const els = document.querySelectorAll('.countdown')
if (!els || !els.length) {
return
}
els.forEach(function (el) {
el.countdown = new CountdownTimer(el, { src_location: CURRENT_SCRIPT })
})

Adding support for timers in renderUI in Shiny is both non-trivial and not super hard. Thanks for offering to do a PR but I'll try to fix this soon.

@gadenbuie gadenbuie added status: planned Planning to implement type: new New feature or enhancement priority: high High priority labels Apr 1, 2024
@gadenbuie gadenbuie self-assigned this Apr 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority: high High priority status: planned Planning to implement type: new New feature or enhancement
Projects
None yet
Development

No branches or pull requests

2 participants