I am trying to lift state of the number of bins one level up from a module. This is a common technique in react, and I suspect shiny as well, when some data needs to be shared between different components (modules in shiny parlance)
This is the code I currently have
ui.R
library(shiny)
library(shinydashboard)
source("modules/my.R", local=my <- new.env())
ui <- dashboardPage(
dashboardHeader(title="Dashboard"),
dashboardSidebar(
sidebarMenu(
menuItem("App 1", tabName="app1"),
menuItem("App 2", tabName="app2"),
id="selectedMenu"
)
),
dashboardBody(
uiOutput("foo")
)
)
server.R
library(shiny)
source("modules/my.R", local=my <- new.env())
server <- function(input, output) {
reactive = reactive({3})
callModule(my$my, "foo", numBins=reactive)
plot <- my$myUI("foo")
output$foo <- renderUI({
if (input$selectedMenu == "app1") {
return(plot)
} else {
return(br())
}
})
}
and this is the module
library(shiny)
myUI <- function(id) {
ns <- NS(id)
tagList(
fluidRow(
box(
plotOutput(outputId = ns("distPlot")),
width=12
)
),
fluidRow(
box(
sliderInput(inputId = ns("bins"), label = "Number of bins:", min = 1, max = 50, value = 30),
width=12
)
)
)
}
my <- function(input, output, session, numBins) {
output$distPlot <- renderPlot({
numBins()
x <- faithful$waiting
bins <- seq(min(x), max(x), length.out = numBins() + 1)
hist(x, breaks = bins, col = "#75AADB", border = "white",
xlab = "Waiting time to next eruption (in mins)",
main = "Histogram of waiting times")
})
observe({
updateSliderInput(session, "bins", value=numBins())
})
}
I am trying to lift numBins out at the server.R level, and inject it in the module. However, it seems that the plot is not re-rendered. Initialisation seems to work however. I get the right number of bins, but moving the slider does nothing.
Please feel free to comment on other things that look dodgy. I am just a beginner with shiny and R (I do however have experience with react)
Edit
I have a simpler version with just two sliders, trying to make one change when the other is moved, by having numBins shared between the two from below.
library(shiny)
library(shinydashboard)
source("modules/my.R", local=my <- new.env())
ui <- dashboardPage(
dashboardHeader(title="Dashboard"),
dashboardSidebar(),
dashboardBody(
uiOutput("central")
)
)
library(shiny)
source("modules/my.R", local=my <- new.env())
server <- function(input, output) {
numBins = reactiveVal(value=3)
callModule(my$my, "slider1", id="slider1", numBins=numBins)
callModule(my$my, "slider2", id="slider2", numBins=numBins)
output$central <- renderUI({
tagList(
my$myUI("slider1"),
my$myUI("slider2")
)})
}
library(shiny)
myUI <- function(id) {
ns <- NS(id)
fluidRow(
box(
sliderInput(inputId = ns("bins"), label = "Number of bins:", min = 1, max = 50, value = 30),
width=12
)
)
}
my <- function(input, output, session, id, numBins) {
ns <- NS(id)
observeEvent(
numBins,
{
cat("1234", file=stderr())
updateSliderInput(session, ns("bins"), value=numBins())
})
}
Still not working and kind of ugly to have to provide the id twice for the server function.