Rshiny modular application with reactiveValues has session separation issues - r

I have a shiny application for which I have reproduced a simple example here.
It is a modular shiny application. This one is deployed on shinyapp.io
My problem is that when I open 2 instances of my deployed application, the actions done on one of the windows are applied to the other window
It seems that the problem is caused by the reactiveValues (r_global <- reactiveValues() ) in the server part.
Here is the reproduction of the code.
library(shiny)
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# MODULE ----
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
counterButton = function(id, label = "Counter") {
ns = NS(id)
tagList(actionButton(ns("button"), label = label),
verbatimTextOutput(ns("out")),
dataTableOutput(ns("table")))
}
counterServer <- function(id, r_global) {
moduleServer(id,
function(input, output, session) {
r_global$count = 0
observeEvent(input$button, {
r_global$count = r_global$count + 1
if (input$button == 3) {
output$table <- renderDataTable({
mtcars
})
} else{
output$table <- renderDataTable({
iris
})
}
})
output$out <- renderText({
r_global$count
})
})
}
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# UI ----
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ui = fluidPage(h1("test"), counterButton("counter1", "Counter #1"))
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# SERVER ----
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
server <- function(input, output, session) {
r_global <- reactiveValues()
counterServer("counter1", r_global = r_global)
}
shinyApp(ui, server)

Related

module outer variables aren't updating - r shiny

In the main shiny server I have a reactivePoll variable. I am trying to share this updating variable with shiny modules. It shows the initial value but it doesn't update. I am trying to get it to update.
Here is a reprex:
library(shiny)
# Module ----
# module ui
mod_ui <- function(id){
ns = NS(id)
verbatimTextOutput(ns("random_num"))
}
# module server
mod <- function(id, number) {
server <- function(input, output, session) {
output$random_num <- renderPrint(number)
}
moduleServer(id, server)
}
# Shiny App ----
ui <- fluidPage(
tags$span("working random_num"),
verbatimTextOutput("test"),
tags$span("not working, module random num"),
mod_ui("mod_id")
)
server <- function(input, output, session) {
random_num <- reactivePoll(
intervalMillis = 1000,
session = NULL,
checkFunc = function()runif(1),
valueFunc = function()runif(1)
)
output$test <- renderPrint(random_num())
mod("mod_id", number = random_num())
}
shinyApp(ui = ui, server = server)
Any help is greatly appreciated!
Figured a solution. Save the reactivePoll variable into a reactiveValue. Observe the reactiveValue. Curious why this is the case.
library(shiny)
# Module ----
# module ui
mod_ui <- function(id){
ns = NS(id)
verbatimTextOutput(ns("random_num"))
}
# module server
mod <- function(id, number) {
server <- function(input, output, session) {
output$random_num <- renderPrint(number$test)
}
moduleServer(id, server)
}
# Shiny App ----
ui <- fluidPage(
tags$span("working random_num"),
verbatimTextOutput("test"),
tags$span("not working, module random num"),
mod_ui("mod_id")
)
server <- function(input, output, session) {
test <- reactiveValues(
test = runif(1)
)
random_num <- reactivePoll(
intervalMillis = 1000,
session = NULL,
checkFunc = function()runif(1),
valueFunc = function()runif(1)
)
observe(
test$test <- random_num()
)
output$test <- renderPrint(random_num())
mod("mod_id", number = test)
}
shinyApp(ui = ui, server = server)

shinymeta: how to use expandChain in modules?

I'm making an app with modules in which the user can create as many UI as he wants. Each UI contain one table and I would like to give the possibility to the user to see the code for each of this table separately, not in a unique chunk. Therefore, I included the part of the code with expandChain in my module (module_server).
However, expandChain won't detect the reactive stuff I'm calling because the name of this stuff changes since it is created in a module. Take a look at the app below:
library(dplyr)
library(shiny)
library(shinymeta)
library(WDI)
module_ui <- function(id){
ns <- NS(id)
tagList(
fluidRow(
actionButton(ns("show_table"), "Show table"),
actionButton(ns("show_code"), "Show code"),
tableOutput(ns("table"))
)
)
}
module_server <- function(input, output, session){
data <- metaReactive2({
req(input$show_table)
isolate(metaExpr({
mtcars
}))
})
output$table <- renderTable({
data()
})
observeEvent(input$show_code, {
showModal(modalDialog(
renderPrint({
expandChain(data())
})
))
})
}
ui <- fluidPage(
actionButton("launch", "Launch")
)
server <- function(input, output, session) {
count <- reactiveValues(value = 0)
observeEvent(input$launch, {
count$value <- count$value + 1
insertUI(selector = "#launch",
where = "afterEnd",
ui = module_ui(count$value))
callModule(module_server, count$value)
})
}
shinyApp(ui, server)
When I try to show the code for the table generated, I have the error:
Warning: Error in : <text>:2:2: unexpected input
1: `1_data` <- mtcars
2: 1_
^
133: <Anonymous>
Since the module renames data() by adding a number, data() is not recognized by expandChain. I tried with:
expandChain(paste0(id, "_data()"))
without success (since expandChain does not support character).
Does anybody know how to do it?
Also asked on RStudio Community
Here's the solution given on RStudio Community (see the link for some additional details):
library(dplyr)
library(shiny)
library(shinymeta)
library(WDI)
module_ui <- function(id){
ns <- NS(id)
tagList(
fluidRow(
actionButton(ns("show_table"), "Show table"),
actionButton(ns("show_code"), "Show code"),
tableOutput(ns("table"))
)
)
}
module_server <- function(input, output, session){
data <- metaReactive2({
req(input$show_table)
isolate(metaExpr({
mtcars
}))
})
output$table <- renderTable({
data()
})
observeEvent(input$show_code, {
showModal(modalDialog(
renderPrint({
expandChain(data())
})
))
})
}
ui <- fluidPage(
actionButton("launch", "Launch")
)
server <- function(input, output, session) {
count <- reactiveValues(value = 0)
observeEvent(input$launch, {
count$value <- count$value + 1
insertUI(selector = "#launch",
where = "afterEnd",
ui = module_ui(paste0("x", count$value)))
callModule(module_server, paste0("x", count$value))
})
}
shinyApp(ui, server)

eventReactive in shiny module

I would like to use an eventReactive-function in a shiny module. However that does not work as expected. What is wrong with my code or what do I have to add?
I have already tried observers but I want to use eventReactive because I need the return-value.
mod_test_UI <- function(id) {
ns <- NS(id)
actionButton(ns("test"), "Test")
}
mod_test <- function(input, output, session) {
ns <- session$ns
observe({
print(input$test)
})
result<- eventReactive(input$test, {
print("ABC")
})
}
ui <- tagList(
mod_test_UI("test-mod")
)
server <- function(input, output, session) {
callModule(mod_test, "test-mod")
}
# app
shinyApp(ui = ui, server = server)
You need to return a value within eventReactive as below:
mod_test_UI <- function(id) {
ns <- NS(id)
actionButton(ns("test"), "Test")
}
mod_test <- function(input, output, session) {
ns <- session$ns
observe({
print(input$test)
})
result<- eventReactive(input$test, {
return("ABC")
})
observe({
print(result())
})
}
ui <- tagList(
mod_test_UI("test-mod")
)
server <- function(input, output, session) {
callModule(mod_test, "test-mod")
}
# app
shinyApp(ui = ui, server = server)
The second observe just prints the value now contained in result() to the screen to prove that it works.
The return() in this case is not necessary and it could just be "ABC" as below:
result<- eventReactive(input$test, {
"ABC"
})

How to store the returned value from a Shiny module in reactiveValues?

Version 1 below is a toy module that asks for a user input txt, and return the input to the main Shiny app. The main Shiny app then render the text and output it to the screen.
Here I store the return value of the module in a variable called mytxt and I called it through renderText({ mytxt() }).
However, what I actually want to do is to store the returned value to reactiveValues in the main Shiny app. (It doesn't matter if I output it or not as I want to do further evaluations on that value.) But sadly I found no way in making it works. I'm showing my failed codes in Version 2 below.
Version 1 (Correct)
app.R
library(shiny)
source("module_1.R")
ui <- fluidPage(
returnUI("returntxt"),
textOutput("mytxt")
)
server <- function(input, output, session) {
mytxt <- callModule(returnServer, "returntxt")
output$mytxt <- renderText({ mytxt() })
}
shinyApp(ui, server)
module_1.R
returnUI = function(id) {
ns <- NS(id)
tagList(
textInput(ns("txt"), "Write something")
)
}
returnServer = function(input, output, session) {
mytxt <- reactive({
input$txt
})
return(mytxt)
}
Version 2 (Need help!)
app.R
library(shiny)
source("modules/module_1.R")
ui <- fluidPage(
returnUI("returntxt"),
textOutput("mytxt")
)
server <- function(input, output, session) {
myvals <- reactiveValues(
txt = NULL
)
mytxt <- callModule(returnServer, "returntxt")
myvals$txt <- isolate(mytxt())
output$mytxt <- renderText({ myvals$txt })
}
shinyApp(ui, server)
module.R is the same as Version 1.
I just found the answer by returning reactiveValues from the module and use observe :) Woohoo!
app.R
library(shiny)
source("modules/module_1.R")
ui <- fluidPage(
returnUI("returntxt"),
textOutput("mytxt")
)
server <- function(input, output, session) {
myvals <- reactiveValues(
txt = NULL
)
mytxt <- callModule(returnServer, "returntxt")
observe({
myvals$txt <- mytxt$txt
print(myvals$txt)
})
output$mytxt <- renderText({ myvals$txt })
}
shinyApp(ui, server)
module_1.R
returnUI = function(id) {
ns <- NS(id)
tagList(
textInput(ns("txt"), "Write something")
)
}
returnServer = function(input, output, session) {
myreturn <- reactiveValues()
observe({ myreturn$txt <- input$txt })
return(myreturn)
}

Using shiny's renderUI in Module

this is my first question at stackoverflow. I have a problem with modules and renderUI in shiny (1.0.5).
When I use renderUI in
#### Main Part
ui <- bootstrapPage(
uiOutput("DynamicContent")
)
server <- function(input, output,session) {
S_A <- selectInput("S_A_Input" ,"Change Me for print message",choices=1:3 )
output$DynamicContent <- renderUI({
tagList(S_A)
})
observe({
print(input$S_A_Input)
})
}
shinyApp(ui = ui, server = server)
then changing the selectInput will cause changing input$S_A_Input, so the print will occur. That's fine.
On the other hand, input$S_A_Input seems not to work, if I work with modules:
### Module Part
Module_YYY_Server <- function(input, output, session){
S_A <- selectInput("S_A_Input" ,"Change Me for print message",choices=1:3 )
output$DynamicContent <- renderUI({
tagList(S_A)
})
observe({
print(input$S_A_Input)
})
}
Module_YYY_Ui <- function(id){
ns <- NS(id) # Creates Namespace
tagList(
uiOutput("DynamicContent" %>% ns)
)
}
And then calling the module.
#### Main Part
ui <- bootstrapPage(
Module_YYY_Ui("YYY")
)
server <- function(input, output,session) {
callModule(Module_YYY_Server,"YYY")
}
shinyApp(ui = ui, server = server)
I haven't found a solution to this behaviour.
Late to the party but this is another option to solve your problem using
session$ns("id")
Here how it looks like:
Module_YYY_Server <- function(input, output, session){
output$DynamicContent <- renderUI({
selectInput(session$ns("S_A_Input"), "Change Me for print message", choices = 1:3)
})
output$text <- renderText({
req(input$S_A_Input)
input$S_A_Input})
}
Module_YYY_Ui <- function(id){
ns <- NS(id) # Creates Namespace
tagList(
uiOutput(ns("DynamicContent")),
textOutput(ns("text"))
)
}
ui <- bootstrapPage(
Module_YYY_Ui("YYY")
)
server <- function(input, output,session) {
callModule(Module_YYY_Server,"YYY")
}
shinyApp(ui = ui, server = server)
This is based on the example here
While I am sure your example is simplified, If your input$S_A_Input is not changing based on what you are doing, as is the case in your example, I would not recommend using renderUI. Regardless of that, the reason that your input is not printing is because you are not generating it as an output.
Module_YYY_Server <- function(input, output, session){
output$DynamicContent <- renderUI({
ns <- session$ns
tagList(
selectInput("S_A_Input" %>% ns, "Change Me for print message",choices=1:3 )
)
})
output$text <- renderText({input$S_A_Input})
}
Module_YYY_Ui <- function(id){
ns <- NS(id) # Creates Namespace
tagList(
uiOutput("DynamicContent" %>% ns),
textOutput("text" %>% ns)
)
}

Resources