I have an app where I update a uiOutput with new content, and then need to run a javascript function on the client side to manipulate it. I'm using shinyjs::runjs() to run the javascript, using observeEvent() when the HTML content, contained in a reactive(), changes.
The timing of the events, however, is that the javascript runs before the page is updated. I would like to have the javascript run after the DOM is updated with the new content from the server.
Here's a reproducible example (the use of setTimeout is only for demonstration of the delay):
---
title: Test
output: flexdashboard::flex_dashboard
runtime: shiny_prerendered
---
```{r, echo=FALSE}
shiny::addResourcePath("shinyjs", system.file("srcjs", package = "shinyjs"))
```
```{r, context='server'}
shinyjs::useShinyjs(html = TRUE)
```
<script src="shinyjs/inject.js"></script>
Column {.sidebar}
------------------------------------
```{r}
shiny::numericInput('js_time', label = 'JS timeout (ms)', min = 0, step = 100, value = 0)
actionButton('button', 'Update')
```
Column
------------------------------------
```{r context='render'}
uiOutput("contentBox")
```
```{r context='server'}
content <- reactive({
input$button
x = rnorm(1)
shiny::tags$div(x, id = 'mydiv')
})
output$contentBox <- renderUI({
content()
})
observeEvent(content(), {
js_time = isolate(input$js_time)
js = glue::glue('setTimeout(function(){{ console.log($("#mydiv").text()); }}, {js_time});')
shinyjs::runjs(js)
})
```
When you check the console, you can see that if you don't set a delay in the javascript (0ms in the setTimeout), the console.log report of the random number is lagged:
However, if you set a timeout of 100ms, the javascript code runs after the DOM is updated and the output is no longer lagged:
My question is: using shiny, is there a natural way of ensuring that javascript will run after the DOM is updated?
(not sure it is relevant, but I will also mention that in my actual application, the DOM may not contain the same elements -- and the javascript may not be run -- on every update)