This is a server function that runs like a callback when the next time
any input value changes. This is useful for to watch dynamically added components from
the server and then do something. For example, loading a
shiny module UI from server by renderUI
and loading
the shiny module server from server by moduleServer
. Loading the server must
wait until renderUI
is finished. However, in shiny renderUI
is asynchronous.
It means moduleServer
is immediately executed after renderUI
. The result
is module's server part cannot find the UI, because it is still updating.
This function is hack to solve this problem by waiting for the next input
settlement operation called from Shiny javascript to R so one can start
other server actions.
onNextInput(expr, session = getDefaultReactiveDomain())
code expression, wrap inside {}
shiny session
an observeEvent that runs only one time to watch for the next input change.
This function adds a on.exit
statement to the parent observer
, renderXX
,
and other reactive events, so make sure you use them inside these functions
instead of plain server.
server = function(input, output, session) {
# ok
output$someID <- renderUI({
onNextInput({...})
div(...)
})
# following is not ok
onNextInput({...})
}
This function fixes the issue in shiny #3348. Until there is an official support for this feature, this function is useful.
if(interactive()){
library(shiny)
# Simple example
ui <- fluidPage(
uiOutput("someui")
)
server <- function(input, output, session) {
output$someui <- renderUI({
# we update the text of new rendered text input to 3 random letters
# after `textInput` is displayed, and it only works for one time.
onNextInput({
updateTextInput(inputId = "mytext", value = paste0(sample(letters, 3), collapse = ""))
})
textInput("mytext", "some text")
})
# if you directly have update event like following line, it won't work
# updateTextInput(inputId = "mytext", value = paste0(sample(letters, 3), collapse = ""))
}
shinyApp(ui, server)
# complex example with modules
modUI <- function(id) {
ns <- NS(id)
textInput(ns("mytext"), "some text")
}
modServer = function(id) {
moduleServer(
id,
function(input, output, session) {
updateTextInput(inputId = "mytext", value = paste0(sample(letters, 3), collapse = ""))
}
)
}
ui = fluidPage(
actionButton("a", "load module UI"),
uiOutput("mod_container")
)
server = function(input, output, session) {
# everytime you click, render a new module UI and update the text value
# immediately
observeEvent(input$a, {
output$mod_container <- renderUI({
onNextInput(modServer("mod"))
modUI("mod")
})
})
# Without `onNextInput`, module server call will not work
# uncomment below and, comment `onNextInput` line to see the difference
# modServer("mod")
}
shinyApp(ui, server)
}