I have problem with communication between main server
and server module
. I would like to return from module current reactiveVals
and then use them in main app.
I created basic app which shows my problem. Module contains 2 buttons and 2 reactiveVals
, each of them contains the number of clicks on the corresponding button.
in the main server, I would like to know which value has changed and react to this change with some action (in the example, a change in the returned text).
unfortunately, the code below returns values from the module only at the time of its launch, then, if there are changes inside the module that we are interested in, I am not informed about it.
How should I modify the code below to get the effect I am interested in?
library(shiny)
moduleUI <- function(id){
ns <- NS(id)
wellPanel(
fluidRow(
column(3, uiOutput(ns("button1"))),
column(3, uiOutput(ns("button2")))
)
)
}
moduleServer <- function(input, output, session){
rv_button1 <- reactiveVal(0)
rv_button2 <- reactiveVal(0)
observeEvent(input$button1, {
rv_button1(rv_button1()+1)
print(rv_button1())
})
observeEvent(input$button2, {
rv_button2(rv_button2()+1)
print(rv_button2())
})
output$button1 <- renderUI({
actionButton("button1", label = "button 1")
})
output$button2 <- renderUI({
actionButton("button2", label = "button 2")
})
return(
list(
button1 = rv_button1,
button2 = rv_button2
)
)
}
ui <- fluidPage(
moduleUI("moduleId"),
fluidRow(uiOutput("text"))
)
server <- function(input, output, session) {
rv_module <- reactiveVal(
list(
button1 = 0,
button2 = 0
)
)
rv_text <- reactiveVal("")
rv_module <- callModule(moduleServer, "moduleId")
observeEvent(rv_module$button1, {
rv_text("Button 1 was clicked")
})
observeEvent(rv_module$button2, {
rv_text("Button 2 was clicked")
})
output$text <- renderUI({
HTML(rv_text())
})
}
runApp(shinyApp(ui, server))
Few things first :
ns()
to your inputId
in a module, even if it is server side.button1
for the button
AND the uiOutput
, it won't work.Then, to communicate between server and module, or between several module, the easiest way is to pass a reactiveValues
as a parameter of your module.
library(shiny)
moduleUI <- function(id){
ns <- NS(id)
column(3, uiOutput(ns("uibutton1"))),
column(3, uiOutput(ns("uibutton2")))
}
moduleServer <- function(input, output, session, rv){
ns <- session$ns # don't forget ns in server side module
observeEvent(input$button1, {
rv$btn1 <- rv$btn1 +1
})
observeEvent(input$button2, {
rv$btn2 <- rv$btn2 +1
})
# do not use the same outputId
output$uibutton1 <- renderUI({
actionButton(ns("button1"), label = "button 1") # use ns()
})
output$uibutton2 <- renderUI({
actionButton(ns("button2"), label = "button 2")
})
}
ui <- fluidPage(
moduleUI("moduleId"),
uiOutput("text")
)
server <- function(input, output, session) {
# Initialise a reactiveValues
rv_module <- reactiveValues(btn1 = 0, btn2 = 0)
callModule(moduleServer, "moduleId", rv = rv_module)
output$text <- renderUI({
paste("btn1 : ",rv_module$btn1, " | btn2 : ", rv_module$btn2)
})
}
runApp(shinyApp(ui, server))