i am using R6 to pass variables across and along the main server and server modules, following Jiwan Heo's approach as described in his article.
Using a simplified example (without graph to minimise code length) of the mentioned article, this works:
library(shiny)
library(dplyr)
library(ggplot2)
library(shinydashboard)
IrisR6 <- R6::R6Class(
"IrisR6",
public = list(
n_rows = NULL,
multiplier = NULL,
orig_data = iris,
res_data = NULL,
manip_data = function(dat) {
dat %>%
head(self$n_rows) %>%
mutate(Sepal.Length = Sepal.Length * self$multiplier)
}
)
)
mod_manip_ui <- function(id) {
ns <- NS(id)
tagList(
numericInput(ns("n_rows"),
"Number of rows to display",
value = 10,
min = 1,
max = 150),
numericInput(ns("multiplier"),
"A random calculation",
value = 1,
min = 1,
max = 10),
actionButton(ns("go"), "Go!")
)
}
mod_manip_server <- function(id, r6) {
moduleServer(id, function(input, output, session) {
observeEvent(input$go, {
r6$n_rows <- input$n_rows
r6$multiplier <- input$multiplier
new_data <- r6$manip_data(dat = r6$orig_data)
r6$res_data <- new_data
gargoyle::trigger("update_iris")
})
})
}
mod_table_ui <- function(id, r6) {
ns <- NS(id)
tagList(
textOutput(ns("text")),
###### This doesn't work ######
# shinydashboard::valueBox(
# value = r6$n_rows,
# subtitle = "nr of rows"
# ),
###############################
###### This works: ######
shinydashboard::valueBox(
value = rnorm(1),
subtitle = "random nr"
),
#########################
tableOutput(ns("table"))
)
}
mod_table_server <- function(id, r6) {
moduleServer(id, function(input, output, session) {
observeEvent(gargoyle::watch("update_iris"), {
output$text <- renderText(paste("Multiplier:", r6$multiplier))
output$table <- renderTable({
req(!is.null(r6$res_data))
r6$res_data
})
})
})
}
ui <- fluidPage(
column(12, mod_manip_ui("mod_manip_1")),
column(6, mod_table_ui("mod_table_1"))
)
server <- function(session, input, output) {
r6 <- IrisR6$new()
gargoyle::init("update_iris")
mod_manip_server("mod_manip_1", r6 = r6)
mod_table_server("mod_table_1", r6 = r6)
mod_graph_server("mod_graph_1", r6 = r6)
}
shinyApp(ui, server)
Now if you look to mod_table_ui()
and use r6$n_rows
as an argument of valueBox()
the code doesn't work (see the commented part inside the mod_table_ui()
of the code above).
What is the best approach to pass external variables defined in the main server of server modules, as arguments of functions used inside the main or modular ui?
As suggested by Stéphane's comment above, using renderUI()
allows to pass variables available in the server to arguments of functions used normally at the UI. So replacing mod_table_ui()
and mod_table_server()
from the code above with the functions below will do the job:
mod_table_ui <- function(id) {
ns <- NS(id)
tagList(
textOutput(ns("text")),
uiOutput(ns('renderUIway')),
tableOutput(ns("table"))
)
}
mod_table_server <- function(id, r6) {
moduleServer(id, function(input, output, session) {
observeEvent(gargoyle::watch("update_iris"), {
output$text <- renderText(paste("Multiplier:", r6$multiplier))
output$table <- renderTable({
req(!is.null(r6$res_data))
r6$res_data
})
output$renderUIway <- renderUI({
tagList(
###### This now also works! ######
shinydashboard::valueBox(
value = r6$n_rows,
subtitle = "nr of rows"
)
###############################
###### This works: ######
# shinydashboard::valueBox(
# value = rnorm(1),
# subtitle = "random nr"
# )
#########################
)
})
})
})
}