Wait for an object to be rendered before adding a JS event listener?

Hi! Thanks for taking a look at this. Reproducing this problem requires the development version of visNetwork devtools::install_github("datastorm-open/visNetwork"), but maybe you know how to fix this without running the repex.

I would like to trigger an event when a button inside of a visNetwork widget is pressed. However, adding an event listener after the document loads does not work.

I suspect that this is because that button is not rendered after $document.ready().

At the bottom of this post is a reprex with (1) a simple button, as a positive control/test, and (2) a visNetwork widget.

Problem explanation

In visNetwork, you can "edit" an edge, like so:

I want to call a function whenever the user presses the "save" button.

That button has an id:

image

So, in the reprex below, I add an event listener to that id:

$("#editedge-saveButton").click(
    function() {
        alert("Thanks for saving!")
    });

But it doesn't work, even though a similar event listener for a test button does work:

Note that, if I add that event listener in the console after I load the app, it works just fine:

Reprex

library(shiny)
library(visNetwork)

ui <- fluidPage(
  tags$head(
    tags$script(
      type = "text/javascript",
      '
      $(document).ready(function() {
      
      // Positive control: an alert for a button
      $("#clickme").click(
        function() {
            alert("Here is an alert!");
        });
        
      // This is what I am having trouble with
      $("#editedge-saveButton").click(
        function() {
          alert("Thanks for saving!")
        });
  
      })
      '
    )
  ),
  actionButton("clickme", "Click me for an alert!"),
  visNetworkOutput("mygraph")
)

server <- function(input, output, session) {
  output$mygraph <- renderVisNetwork(
    visNetwork(
      nodes = data.frame(id = "A", label = "A"),
      edges = data.frame(to = "A", from = "A", label = "A to A")
    ) %>%
      visOptions(manipulation = list(
        enabled = TRUE,
        editEdgeCols = c("label")
      ))
  )
}

shinyApp(ui, server)
1 Like

After waiting a day, I went ahead and cross-posted on StackOverflow here: https://stackoverflow.com/questions/62794827/r-shiny-run-js-after-htmlwidget-renders

Stéphane Laurent gave a fantastic answer (as usual) on the StackOverflow post, if anyone else is interested:

Basically you can just set an event listener on the HTML body:

$("body").on("click", "#editedge-saveButton", 
  function() {
    alert("Thanks for saving!")
  }
);

Or you can use the super-handy htmlwidgets::onRender() function.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.