6PO0222
6PO0222

Reputation: 131

Cannot run JavaScript code when Shiny `renderUI` is used

I am trying to apply a JS script (a 'Select all' box) to a dynamically rendered UI, but the following does not work:

library(shinyjs)

ui <- fluidPage(
    useShinyjs(),
    
    uiOutput("checkbox_ui")
)

server <- function(input, output, session) {
    
    output$checkbox_ui <- renderUI({
        checkboxGroupInput(inputId = "myCheckbox",
                           label = NULL,
                           choices = c("All", "A", "B"))
    })
    
    runjs(HTML("
        $(\"#myCheckbox input[value='All']\").click(function(e) {
            $(\"#myCheckbox input[type='checkbox']\").prop('checked', $(e.target).prop(\"checked\"));
        });
    "))
}

shinyApp(ui, server)

However, when I skip using renderUI, the JS script is ran:

library(shinyjs)

ui <- fluidPage(
    useShinyjs(),
    
    checkboxGroupInput(inputId = "myCheckbox",
                       label = NULL,
                       choices = c("All", "A", "B"))
)

server <- function(input, output, session) {
    
    runjs(HTML("
        $(\"#myCheckbox input[value='All']\").click(function(e) {
            $(\"#myCheckbox input[type='checkbox']\").prop('checked', $(e.target).prop(\"checked\"));
        });
    "))
}

shinyApp(ui, server)

Would someone know a workaround?

Upvotes: 0

Views: 571

Answers (2)

St&#233;phane Laurent
St&#233;phane Laurent

Reputation: 84529

That's because the checkbox is not rendered yet when runjs is executed.

I would try:

runjs(HTML("setTimeout(function(){
        $(\"#myCheckbox input[value='All']\").click(function(e) {
            $(\"#myCheckbox input[type='checkbox']\").prop('checked', $(e.target).prop(\"checked\"));
        });
    });"))

and if that doesn't work, I would try

observeEvent(input[["myCheckbox"]], {
  runjs(HTML("
        $(\"#myCheckbox input[value='All']\").click(function(e) {
            $(\"#myCheckbox input[type='checkbox']\").prop('checked', $(e.target).prop(\"checked\"));
        });
    "))
})

EDIT

Here is a working solution, without using shinyjs:

library(shiny)

js <- paste(
  "$(document).ready(function(){",
  "  $('body').on('click', \"#myCheckbox input[value='All']\", function(e) {",
  "    var isChecked = $(e.target).prop('checked');",
  "    $(\"#myCheckbox input[value!='All']\").prop('checked', isChecked);",
  "  });",
  "});",
  sep = "\n"
)

ui <- fluidPage(
  tags$head(tags$script(HTML(js))),
  uiOutput("checkbox_ui")
)

server <- function(input, output, session) {
  
  output$checkbox_ui <- renderUI({
    checkboxGroupInput(inputId = "myCheckbox",
                       label = NULL,
                       choices = c("All", "A", "B"))
  })
  
}

shinyApp(ui, server)

Upvotes: 4

YBS
YBS

Reputation: 21297

The following works fine.

js <- "
        $(\"#myCheckbox input[value='All']\").click(function(e) {
            $(\"#myCheckbox input[type='checkbox']\").prop('checked', $(e.target).prop(\"checked\"));
        });
    "

library(shinyjs)

ui <- fluidPage(
  useShinyjs(),
  
  checkboxGroupInput(inputId = "myCheckbox",
                     label = NULL,
                     choices = c("All", "A", "B"))
)

server <- function(input, output, session) {
  
  observeEvent(input[["myCheckbox"]], {
    updateCheckboxGroupInput(session,"myCheckbox")
    runjs(HTML(js))
  }, ignoreNULL = FALSE)

}

shinyApp(ui, server)

output

With renderUI

ui <- fluidPage(
  useShinyjs(),
  
  uiOutput("uic")
)

server <- function(input, output, session) {
  
  output$uic <- renderUI({
    checkboxGroupInput(inputId = "myCheckbox",
                       label = NULL,
                       choices = c("All", "A", "B"))
  })
  
  observeEvent(input[["myCheckbox"]], {
    updateCheckboxGroupInput(session,"myCheckbox")
    runjs(HTML(js))
  }, ignoreNULL = FALSE)
  
}

shinyApp(ui, server)

Upvotes: 2

Related Questions