'shiny insertUI with an init empty cycle

All inputs should be available from the first line of code in the shiny app server. When we use shiny::insertUI (even with immediate option) with shiny inputs then we have to wait for a reactive cycle to see inputs added by shiny::insertUI.
Is there a way to update the inputs just after UI is inserted, like any session$ method.

In the first cycle of the example the input$sth is empty (NULL).

Please check the app example and comments.

Notice: commented browser calls inside the app.

library(shiny)

ui <- fluidPage(
  titlePanel("Old Faithful Geyser Data"),
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30),
      div(id = "input_example")
    ),
    mainPanel(
      plotOutput("distPlot")
    )
  )
)

server <- function(input, output, session) {
  session$onFlush( function() message("Start flush"), once = FALSE)
  session$onFlushed( function() message("End flush"), once = FALSE)
  # immediate inset
  # in the web-browser console `Shiny.shinyapp.$inputValues['sth']` is obviously empty
  # browser()
  session$sendInsertUI(selector = "#input_example", multiple = FALSE, where = "beforeBegin",
                       content = htmltools::doRenderTags(textInput(session$ns("sth"), "sth", "sth")))
  #
  # Here I want to restart/refresh the session, 
  # i.e. transfer the input from the webbrowser session to the session object
  #  

  output$distPlot <- renderPlot({
    # req(input$sth) is NOT what I am looking for
    # input$sth is NOT visible in the first cycle.
    # However in the web-browser console `Shiny.shinyapp.$inputValues['sth']` is NOT empty
    # browser()
    print(paste("input$bins:", deparse1(input$bins)))
    print(paste("input$sth:", deparse1(input$sth)))
    x <- faithful[, 2]
    bins <- seq(min(x), max(x), length.out = input$bins + 1)
    hist(x, breaks = bins, col = 'darkgray', border = 'white')
  })
}

shinyApp(ui = ui, server = server)

# Listening on http://127.0.0.1:7193
# [1] "input$bins: 30L"
# [1] "input$sth: NULL"
# Start flush
# End flush
# [1] "input$bins: 30L"
# [1] "input$sth: \"sth\""
# Start flush
# End flush

EDIT:

I get a response on my issue on github https://github.com/rstudio/shiny/issues/3637

Unfortunately it seems there is no solution for this case. We have to accept how it behaves.

" It’s not possible to implement any command that blocks until the next browser message, which is what I think you’re asking for. However, I can think of two workarounds.

The first is to use freezeReactiveValue(input, "sth") right after the insertUI call. This causes any reactives that try to read input$sth to abort (similar to req(FALSE), until the next browser message (basically). This is exactly what freezeReactiveValue is intended for.

The second possibility is to define your outputs, etc. inside of an observeEvent(input$sth, once=TRUE, {…}) (you may also want to pass ignoreNULL=FALSE, ignoreInit=TRUE if you want those outputs, etc. to be defined even if input$sth has a NULL value even after the input is initialized). "



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source