call back when Shiny renderUI is done

Hi guys,

Is there a call back on renderUI, so when the rendering is done I can do something? detailed description is posted here: https://stackoverflow.com/questions/66792537/call-back-when-shiny-renderui-is-done

Seems to me you could use shiny modules ...

Actually I am using modules, but some modules are coming from other packages. So when I need to load the module UI and server dynamically, there is this time difference between UI loading and server loading. I am looking for a way to wait for UI loading to finish before I can load the server. Otherwise, errors will happen.

I attempted a reprex that has a similar structure to yours, a dependent module 'requires' meaningful values to exist in the last numeric inpt which will be added on the button press.


library(shiny)
somemod_UI <- function(id) {
  ns <- NS(id)
  div(style="display:block;",
    p("my mod"),
    br(),
    uiOutput(ns("mod"))
  )
}
somemod_Server <- function(id,external_value) {
  moduleServer(
    id,
    function(input, output, session) {
      output$mod <- renderUI({
        tagList(
          p(paste0("external value is ", req(external_value())))
        )
      })
      return(reactive(req(external_value())^2))
    }
  )
}

ui <- fluidPage(
  actionButton("a", "add UI"),
  div(style="display:flex;",
  uiOutput("ui_out"),
  somemod_UI("s1")
))


server <- function(input, output, session) {
  # flags <- reactiveValues()
  observeEvent(input$a, {
    output$ui_out <- renderUI({
      lapply(1:10, function(i) {
        numericInput(paste0("n", i), paste0("n", i), value = 0)
      })
    })
     # flags$a <- TRUE
  })
  # observeEvent(flags$a, {
  #     print("observed the flag ...")
  # })

  
   s1 <-  somemod_Server(id = "s1",
                     external_value = reactive(input$n10))
  observeEvent(s1(),
               print(s1()))
  
}

shinyApp(ui, server)

Here is the module rewriting:

somemod_UI <- function(id) {
    ns <- NS(id)
    div(style="display:block;",
        lapply(1:10, function(i) {
            numericInput(paste0(ns("n"), i), paste0("n", i), value = 0)
        })
    )
}

somemod_Server <- function(id) {
    moduleServer(
        id,
        function(input, output, session) {
            observe(
                if (input$n10 > 0) print(1)
            )
        }
    )
}

ui <- fluidPage(
    actionButton("a", "add UI"),
    div(style="display:flex;",
        uiOutput("ui_out")
    ))


server <- function(input, output, session) {
    # flags <- reactiveValues()
    observeEvent(input$a, {
        output$ui_out <- renderUI({
            somemod_UI("s1")
        })
        somemod_Server("s1")
    })

    
}

shinyApp(ui, server)

Like I said, the module is loaded dynamically, so I cannot call the UI on main UI (fluidPage), it has to go inside the renderUI, and then call the server somemod_Server -- whole UI and server are loaded through server on button click, no preloading.

Second, the module is not written by me, I am just loading the module, so I cannot use any "requirement" req statement. The author of the module may or may not use req in the module server, but I don't know. I need to think the worst -- what if they don't use. So just imagine you cannot change anything inside the module server. It will work if I preload everything but will not work if I dynamically load.

ok, as your recent version of the modular example shows, the modular approach can work well with loading on demand (no preloading), and the question is then whether a module is 'well behaved' i.e. its server code takes pains to guard its ui code, or not.

If not, my belief is that you will be fighting a losing battle to integrate it successfully into your wider app.

The module creator should use req(), (or validate/need ), or whatever methods are best for the modules use case so that it does not error. If a module is poorly coded, then you can hack around it, and hope... I suppose you could try spawning an async process thread that waits arbitrary time, until its 'likely' that the module UI is loaded and bound to the shiny session, before attempting to load, but that will somewhat complicate your code, and require you to do statistical analaysis i would think to find appropriate lengths of time to wait,...
To me this all seems much worse than accepting unreliable modules into a project.

but I wish you all the best , if you do find an elegant solution, I do hope you will share it. I expect it will blow my mind !
If you need to think 'the worst', and need to allow some unknown time for the ui to load before attempting to load the ui, you could presumably

Here is the temp solution from Shiny core team: add call back when `renderUI` is done · Issue #3348 · rstudio/shiny · GitHub

Great that you got Joe's attention and he had a solution for you. Thanks very much for sharing back.

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

If you have a query related to it or one of the replies, start a new topic and refer back with a link.