R Shiny: How can I return reactive values from a shiny module to the master server function? - r

I have a simple toy example that uses an add/removeBtn module to add and remove UI from "first" module. I need to keep track of the number of times add/remove has been clicked. If I do not use modules, it is easy, but I am trying to do this in the context of nested modules. Code is below, but basically, I cannot seem to get access to the return from the addRmBtnServer() in the main server function. I am sure it is a simple fix, but I have tried many ways around this, but cannot seem to get access to the result from my call to addRmBtnServer(). Thanks!
library(shiny)
firstUI <- function(id) { uiOutput(NS(id, "first")) }
firstServer <- function(input, output, session, a) {
output$first <- renderUI({
selectInput(session$ns("select"), h4("Select"), paste0(isolate(a()),letters[1:4]))
})
}
removeFirstUI <- function(id) {
removeUI(selector = paste0('#', NS(id, "first")))
}
addRmBtnUI <- function(id) {
ns <- NS(id)
tags$div(
actionButton(inputId = ns('insertParamBtn'), label = "Add"),
actionButton(ns('removeParamBtn'), label = "Remove"),
hr(),
tags$div(id = ns('placeholder'))
)
}
addRmBtnServer <- function(input, output, session, moduleToReplicate, ...) {
ns = session$ns
params <- reactiveValues(btn = 0)
observeEvent(input$insertParamBtn, {
params$btn <- params$btn + 1
callModule(moduleToReplicate$server, id = params$btn, ...)
insertUI(
selector = paste0('#', ns('placeholder')),
ui = moduleToReplicate$ui(ns(params$btn))
)
})
observeEvent(input$removeParamBtn, {
moduleToReplicate$remover(ns(params$btn))
params$btn <- params$btn - 1
})
return(params$btn)
}
ui <- fluidPage(
addRmBtnUI("addRm"),
textInput("a", label = "a", value = 1, width = '150px'),
verbatimTextOutput("view", placeholder = TRUE)
)
server <- function(input, output, session) {
pars <- callModule(
addRmBtnServer, id = "addRm",
moduleToReplicate = list(
ui = firstUI,
server = firstServer,
remover = removeFirstUI
),
)
output$view <- renderText({ pars() })
}
shinyApp(ui = ui, server = server)

As said in the comment, you can pass the values as return values in the corresponding server functions. There is a working example below. I left out the firstUI, firstServer and removeFirstUI implementations since they are irrelevant for your problem.
library(shiny)
addRmBtnUI <- function(id) {
ns <- NS(id)
tags$div(
actionButton(inputId = ns('insertParamBtn'), label = "Add"),
actionButton(ns('removeParamBtn'), label = "Remove"),
hr(),
tags$div(id = ns('placeholder'))
)
}
addRmBtnServer <- function(input, output, session, moduleToReplicate, ...) {
ns = session$ns
params <- reactiveValues(btn = 0)
observeEvent(input$insertParamBtn, {
params$btn <- params$btn + 1
callModule(moduleToReplicate$server, id = params$btn, ...)
insertUI(
selector = paste0('#', ns('placeholder')),
ui = moduleToReplicate$ui(ns(params$btn))
)
})
observeEvent(input$removeParamBtn, {
moduleToReplicate$remover(ns(params$btn))
params$btn <- params$btn - 1
})
return(reactive({params$btn}))
}
ui <- fluidPage(
addRmBtnUI("addRm"),
verbatimTextOutput("view", placeholder = TRUE)
)
server <- function(input, output, session) {
a <- reactive({input$a})
pars <- callModule(
addRmBtnServer, id = "addRm",
moduleToReplicate = list(
ui = function(...){},
server = function(...){},
remover = function(...){}
)
)
output$view <- renderText({ pars() })
}
shinyApp(ui = ui, server = server)

Related

How to save and restore bookmark state using rds file instead of copying and pasting url?

I'm trying to run a shiny app locally on my desktop and I'm looking for a way to download and upload the bookmark state as an rds file instead of copying and pasting a url. I've tried workarounds but they are not as helpful as using shiny's bookmark functions and features. Here is an example app which has the bookmark function. I'm trying to convert this into an app that can download and upload rds file to save and restore the state. Any help will be greatly appreciated.
library(shiny)
library(janitor)
histogramUI <- function(id,var,bins) {
tagList(
fluidRow(column( 4, selectInput(NS(id, "var"), "Variable", choices = names(mtcars),selected=var),
numericInput(NS(id, "bins"), "bins", value = bins, min = 1)),
column(8, plotOutput(NS(id, "hist"))))
)
}
histogramServer <- function(id) {
moduleServer(id, function(input, output, session) {
data <- reactive(mtcars[[input$var]])
output$hist <- renderPlot({
hist(data(), breaks = input$bins, main = input$var)
}, res = 96)
})
}
tableUI <- function(id,var,bins) {
tagList(
fluidRow(column( 4, selectInput(NS(id, "var"), "Variable", choices = names(mtcars),selected=var),
column(8, tableOutput(NS(id, "tab")))))
)
}
tableServer <- function(id) {
moduleServer(id, function(input, output, session) {
data <- reactive(mtcars[[input$var]])
output$tab <- renderTable({
tabyl(data(), main = input$var)
})
})
}
boxUI <- function(id,var) {
tagList(
fluidRow(column( 4, selectInput(NS(id, "var2"), "Variable", choices = names(mtcars),selected=var),
column(8, plotOutput(NS(id, "box"))))
))
}
boxServer <- function(id) {
moduleServer(id, function(input, output, session) {
data <- reactive(mtcars[[input$var2]])
output$box <- renderPlot({
boxplot(data(), main = input$var2)
})
})
}
ui <- function(request){
fluidPage(
bookmarkButton(),
actionButton("add", "Add Histogram"),
actionButton("add2", "Add Boxplot"),
actionButton("add3", "Add Table"),
div(id = "add_here")
)
}
server <- function(input, output, session) {
setBookmarkExclude(c('add','add2','add3'))
add_id <- reactiveVal(0)
add2_id <- reactiveVal(0)
add3_id <- reactiveVal(0)
observeEvent(input$add, {
bins <- 10
histogramServer(paste0("hist_", input$add+add_id()))
insertUI(selector = "#add_here", ui = histogramUI(paste0("hist_", input$add+add_id()),input$var,bins))#}
})
observeEvent(input$add2, {
boxServer(paste0("box_", input$add2+add2_id())) #changed add_id() to add2_id()
insertUI(selector = "#add_here", ui = boxUI(paste0("box_", input$add2+add2_id()), input$var2))
})
observeEvent(input$add3, {
tableServer(paste0("tab_", input$add3+add3_id()))
insertUI(selector = "#add_here", ui = tableUI(paste0("tab_", input$add3+add3_id()), input$var))
})
onBookmark(function(state) {
state$values$modules <- state$exclude
state$values$add <- state$input$add + add_id()
state$values$add2 <- state$input$add2 + add2_id()
state$values$add3 <- state$input$add3 + add3_id()
})
onRestore(function(state){
add_id(state$values$add)
add2_id(state$values$add2)
add3_id(state$values$add3)
modules <- state$values$modules
if (length(modules)>1) {
for (i in 1:(length(modules))) {
if (substr(modules[i],1,4)=='hist') {
histogramServer(modules[i])
insertUI(selector = "#add_here", ui = histogramUI(modules[i],paste0(modules[i],"-var"),paste0(modules[i],"-bin")))
}
if (substr(modules[i],1,3)=='box') {
boxServer(modules[i])
insertUI(selector = "#add_here", ui = boxUI(modules[i],paste0(modules[i],"-var")))
}
if (substr(modules[i],1,3)=='tab') {
tableServer(modules[i])
insertUI(selector = "#add_here", ui = tableUI(modules[i],paste0(modules[i],"-var")))
}
}
}
})
}
shinyApp(ui, server, enableBookmarking = "server")
This question is also posted here

How to generate multiple plots using modules?

I'm trying to create multiple plots using modules, each plot with it's own input. But when I tried to run the app, only the inputs are added each time I add using insertUI and the plot output is blank.
I've tried connecting the ui and the server modules with the same id ("hist1") but it doesn't seem to connect each individual module.
histogramUI <- function(id) {
tagList(
selectInput(NS(id, "var"), "Variable", choices = names(mtcars)),
numericInput(NS(id, "bins"), "bins", value = 10, min = 1),
plotOutput(NS(id, "hist"))
)
}
histogramServer <- function(id) {
moduleServer(id, function(input, output, session) {
data <- reactive(mtcars[[input$var]])
output$hist <- renderPlot({
hist(data(), breaks = input$bins, main = input$var)
}, res = 96)
})
}
ui <- fluidPage(
actionButton("add", "Add"),
div(id = "add_here")
)
server <- function(input, output, session) {
histogramServer("hist1")
observeEvent(input$add, {
insertUI(selector = "#add_here", ui = histogramUI("hist1"))
})
}
shinyApp(ui,server)
Here is a solution where every time you click add you generate a new pair of histogramServer/histogramUI which have the same id (but a different one than the one before, because add gets incremented):
library(shiny)
histogramUI <- function(id) {
tagList(
selectInput(NS(id, "var"), "Variable", choices = names(mtcars)),
numericInput(NS(id, "bins"), "bins", value = 10, min = 1),
plotOutput(NS(id, "hist"))
)
}
histogramServer <- function(id) {
moduleServer(id, function(input, output, session) {
data <- reactive(mtcars[[input$var]])
output$hist <- renderPlot({
hist(data(), breaks = input$bins, main = input$var)
}, res = 96)
})
}
ui <- fluidPage(
actionButton("add", "Add"),
div(id = "add_here")
)
server <- function(input, output, session) {
observeEvent(input$add, {
histogramServer(paste0("hist_", input$add))
insertUI(selector = "#add_here", ui = histogramUI(paste0("hist_", input$add)))
})
}
shinyApp(ui,server)

Using data from one shiny module to another shiny module

I am trying to use a value from one shiny module and pass it to a second shiny module to print it. So when user select orange from first dropdown it show print you have selected orange. But as of now it prints you have selected ATC which is nothing but the id I am passing . Below is the code I am using.Thank you.
library(shiny)
library(shinydashboard)
library(shinyWidgets)
dropDownUI <- function(id, div_width = "col-xs-12 col-md-8") {
ns <- NS(id)
div(column(3, uiOutput(ns("class_level"))),
column(3,uiOutput(ns("selected_product_ui"))
))
}
chartTableBoxUI <- function(id, div_width = "col-xs-12 col-md-8") {
ns <- NS(id)
div(tabBox(width = 12, title = id,
tabPanel(icon("bar-chart"),
textOutput(ns("selected_var")))
)
)
}
chartTableBox <- function(input, output, session, data,ImProxy) {
output$selected_var <- renderText({
ns <- session$ns
paste("You have selected",ns(ImProxy$selected_class))
})
}
dropDown <- function(input, output, session) {
ns <- session$ns
observe({output$class_level <- renderUI({
selectInput(
ns("selected_class"),
label = h4("Classification Level"),
choices = list(
"apple " = "apple",
"orange " = "orange"),
selected = "orange"
)})
})
a<-reactive({input$selected_class})
output$selected_product_ui <- renderUI({
req(input$selected_class)
Sys.sleep(0.2)
ns <- session$ns
if (input$selected_class == "apple") {
my_choices <- c("foo","zoo","boo")
} else if (input$selected_class == "orange") {
my_choices <- c("22","33","44")
} else {
my_choices <- c("aa","bb","cc")
}
selectInput(inputId = ns("selected_product"),
label = h4("Product Family"),
choices = my_choices)
})
}
sidebar <- dashboardSidebar(sidebarMenu(
menuItem("aaa",tabName = "aaa"),
menuItem("bbb", tabName = "bbb"),
menuItem("ccc", tabName = "ccc")
))
body <- ## Body content
dashboardBody(tabItems(
tabItem(tabName = "aaa",
fluidRow(dropDownUI(id = "dropdown"),
fluidRow(chartTableBoxUI(id = "ATC"))
)
)))
# Put them together into a dashboardPage
ui <- dashboardPage(
dashboardHeader(title = "Loyalty Monthly Scorecard"),
sidebar,
body
)
server = {
shinyServer(function(input, output, session) {
callModule(dropDown, id = "dropdown")
callModule(chartTableBox, id = "ATC", data = MyData)
})
}
shinyApp(ui = ui, server = server)
I tried the solution from this question Passing data within Shiny Modules from Module 1 to Module 2 using reactive values and observer event aargument "ImProxy" is missing, with no default
There are two issues with your code:
ImProxy is a user defined variable. You have not defined it, nor have you passed it as an argument.
You are using the id as the title of your tabBox.
Both are corrected below.
library(shiny)
library(shinydashboard)
library(shinyWidgets)
dropDownUI <- function(id, div_width = "col-xs-12 col-md-8") {
ns <- NS(id)
div(column(3,uiOutput(ns("class_level"))),
column(3,uiOutput(ns("selected_product_ui"))
))
}
chartTableBoxUI <- function(id, div_width = "col-xs-12 col-md-8") {
ns <- NS(id)
div(tabBox(width = 12, title = textOutput(ns("title_var")), ## fixing issue 2
tabPanel(icon("bar-chart"),
textOutput(ns("selected_var")))
)
)
}
chartTableBox <- function(input, output, session, data,a) { ## fixing issue 1
output$selected_var <- renderText({
paste("You have selected",a())
})
output$title_var <- renderText({ a() }) ## fixing issue 2
}
dropDown <- function(input, output, session) {
ns <- session$ns
observe({output$class_level <- renderUI({
selectInput(
ns("selected_class"),
label = h4("Classification Level"),
choices = list(
"apple " = "apple",
"orange " = "orange"),
selected = "orange"
)})
})
a<-reactive({input$selected_class})
output$selected_product_ui <- renderUI({
req(input$selected_class)
Sys.sleep(0.2)
ns <- session$ns
if (input$selected_class == "apple") {
my_choices <- c("foo","zoo","boo")
} else if (input$selected_class == "orange") {
my_choices <- c("22","33","44")
} else {
my_choices <- c("aa","bb","cc")
}
selectInput(inputId = ns("selected_product"),
label = h4("Product Family"),
choices = my_choices)
})
return(a) ## fixing issue 1
}
# Put them together into a dashboardPage
ui = dashboardPage(
dashboardHeader(title = "Loyalty Monthly Scorecard"),
dashboardSidebar(sidebarMenu(
menuItem("aaa",tabName = "aaa")
)),
dashboardBody(tabItems(
tabItem(tabName = "aaa",
fluidRow(dropDownUI(id = "dropdown"),
chartTableBoxUI(id = "ATC") # this text
)
)))
)
server = {
shinyServer(function(input, output, session) {
a = callModule(dropDown, id = "dropdown")
callModule(chartTableBox, id = "ATC", data = MyData, a = a)
})
}
shinyApp(ui = ui, server = server)

R Shiny: How to pass reactive variables between nested modules

I have created a toy example in which a textInput() box pops up for the user to input any string, and by clicking the add button, a selectInput() box pops up with the letters a:d prepended with the string. In other words, if the user inputs "1", then by clicking the "add" button, a selectInput() box pops up with 1a, 1b, 1c, and 1d as choices. I am using a module for the add/remove button functionality, and that module calls another module to generate the selectInput() box. The main server function calls the add/remove module, which calls the "first" module, which generates the selectInput() box. I pass a() as a reactive element to add/remove module, which in turn passes this on to "first" module. I just used "..." in the function signature of both the add/remove module and the "first" module to get a() to the nested module.
This seems to work, although a() seems to not be reactive by the time it gets to "first" module, meaning that if I type a different string in the "a" box, I would expect that the choices in the selectInput() box to change dynamically, or at least when I change the textInput() string and click "add", the new selectInput() should reflect the updated textInput() string, but this does not happen. What will make the selectInput() choices change dynamically with changes to textInput()? Code below, thanks!
library(shiny)
firstUI <- function(id) { uiOutput(NS(id, "first")) }
firstServer <- function(input, output, session, a) {
output$first <- renderUI({
selectInput(session$ns("select"), h4("Select"), paste0(a,letters[1:4]))
})
}
removeFirstUI <- function(id) {
removeUI(selector = paste0('#', NS(id, "first")))
}
addRmBtnUI <- function(id) {
ns <- NS(id)
tags$div(
actionButton(inputId = ns('insertParamBtn'), label = "Add"),
actionButton(ns('removeParamBtn'), label = "Remove"),
hr(),
tags$div(id = ns('placeholder'))
)
}
addRmBtnServer <- function(input, output, session, moduleToReplicate,...) {
ns = session$ns
params <- reactiveValues(btn = 0)
observeEvent(input$insertParamBtn, {
params$btn <- params$btn + 1
callModule(moduleToReplicate$server, id = params$btn, ...)
insertUI(
selector = paste0('#', ns('placeholder')),
ui = moduleToReplicate$ui(ns(params$btn))
)
})
observeEvent(input$removeParamBtn, {
moduleToReplicate$remover(ns(params$btn))
params$btn <- params$btn - 1
})
}
ui <- fluidPage(
addRmBtnUI("addRm"),
textInput("a", label = "a", value = 1, width = '150px') )
server <- function(input, output, session) {
a <- reactive({ input$a })
callModule(
addRmBtnServer, id = "addRm",
moduleToReplicate = list(
ui = firstUI,
server = firstServer,
remover = removeFirstUI
), a = a()
)
}
shinyApp(ui = ui, server = server)
If you have
a <- reactive({input$a})
you need to pass a down to the inner (first) module, not a(). That is because a() represents the current value of the observable object a. This means a() is not observable. In your code, a() is evaluated in the server scope during startup. At that time, a has the value 1 (the default value defined in the corresponding textInput) and you pass it as a static object.
You can learn more about reactive values here.
library(shiny)
firstUI <- function(id) { uiOutput(NS(id, "first")) }
firstServer <- function(input, output, session, a) {
output$first <- renderUI({
selectInput(session$ns("select"), h4("Select"), paste0(isolate(a()),letters[1:4]))
})
}
removeFirstUI <- function(id) {
removeUI(selector = paste0('#', NS(id, "first")))
}
addRmBtnUI <- function(id) {
ns <- NS(id)
tags$div(
actionButton(inputId = ns('insertParamBtn'), label = "Add"),
actionButton(ns('removeParamBtn'), label = "Remove"),
hr(),
tags$div(id = ns('placeholder'))
)
}
addRmBtnServer <- function(input, output, session, moduleToReplicate,...) {
ns = session$ns
params <- reactiveValues(btn = 0)
observeEvent(input$insertParamBtn, {
params$btn <- params$btn + 1
callModule(moduleToReplicate$server, id = params$btn, ...)
insertUI(
selector = paste0('#', ns('placeholder')),
ui = moduleToReplicate$ui(ns(params$btn))
)
})
observeEvent(input$removeParamBtn, {
moduleToReplicate$remover(ns(params$btn))
params$btn <- params$btn - 1
})
}
ui <- fluidPage(
addRmBtnUI("addRm"),
textInput("a", label = "a", value = 1, width = '150px') )
server <- function(input, output, session) {
a <- reactive({ input$a })
callModule(
addRmBtnServer, id = "addRm",
moduleToReplicate = list(
ui = firstUI,
server = firstServer,
remover = removeFirstUI
),
a = a
)
}
shinyApp(ui = ui, server = server)
Based on the example here, i've tweaked a little for the desired output.
app.R
library(shiny)
ui <- fluidPage(
actionButton('insertBtn', 'Insert'),
actionButton('removeBtn', 'Remove'),
tags$div(id = 'placeholder'),
textInput(inputId = "a", label = "a", value = 1, width = '150px')
)
server <- function(input, output) {
## keep track of elements inserted and not yet removed
inserted <- c()
observeEvent(input$insertBtn, {
btn <- input$a
id <- paste0('txt', btn)
insertUI(
selector = '#placeholder',
## wrap element in a div with id for ease of removal
ui = tags$div(
selectInput(inputId = btn,label = btn,choices = paste(btn,letters[1:4])),
id = id
)
)
inserted <<- c(id, inserted)
})
observeEvent(input$removeBtn, {
removeUI(
## pass in appropriate div id
selector = paste0('#', inserted[length(inserted)])
)
inserted <<- inserted[-length(inserted)]
})
}
shinyApp(ui = ui, server = server)
This results in app like :
As observed, the selectInputs are added based on a.

R Shiny: How to pass modules as parameters to other modules, and call those modules kin the new module

I am trying to decompose an unwieldy app that I have created, and in doing so I realize that I really need to modularize add/remove buttons. I want to be able to create a shiny module that has an add and remove button, and by clicking those buttons, we can add and remove an instance of another module. To make it simple, I have a toy example that has a simple module that just has a selectInput() IU with 3 choices. I want to be able to add as many of these selectInput() UI elements as desired and be able to access the results of these selections for use in the main server logic. So I created "firstUI()" and firstServer()" modules, as well as "addRmBtnUI()" and "addRmBtnServer()" modules. The addRmBtn modules accept parameters serverModToCall and uiModToCall, which are the names of the ui and server modules that we want to call with the addRmBtn modules. I seem to be getting tripped up on the passing of these modules as parameters to the addRmBtn modules. Code is below. How can I get this to work as intended? Thanks!
suppressWarnings(library(shiny))
firstUI <- function(id) {
ns <- NS(id)
tags$div(
fluidRow(
column(12,
uiOutput(ns("first"))
)
)
)
}
firstServer <- function(input, output, session) {
ns = session$ns
output$first <- renderUI({
selectInput(ns("select"), label = h4("Select"),
choices = list("Selection1" = 1, "Selection2" = 2,
"Selection3" = 3), selected = 1)
})
}
addRmBtnUI <- function(id) {
ns <- NS(id)
tags$div(
fluidRow(
column(2,
uiOutput(ns("insertParamBtn"))
),
column(2,
uiOutput(ns("removeParamBtn"))
)
),
hr(),
tags$div(id = 'placeholder')
)
}
addRmBtnServer <- function(input, output, session, serverModToCall, uiModToCall) {
ns = session$ns
params <- reactiveValues(btn = 0)
output$insertParamBtn <- renderUI({
actionButton(inputId = ns('insertParamBtn'),
label = "Add", offset = 3)
})
output$removeParamBtn <- renderUI({
actionButton(inputId = ns('removeParamBtn'),
label = "Remove", offset = 3)
})
params <- reactiveValues(btn = 0)
observeEvent(input$insertParamBtn, {
params$btn <- params$btn + 1
callModule(do.call(serverModToCall, args = list(id = params$btn)))
insertUI(
selector = '#placeholder',
ui = do.call(uiModToCall, args = list(id = params$btn)) #********# This line is issue
)
})
observeEvent(input$removeParamBtn, {
removeUI(
## pass in appropriate div id
selector = paste0('#param', params$btn)
)
params$btn <- params$btn - 1
})
}
ui <- function(request) {
fluidPage(
fluidRow(
addRmBtnUI(1)
),
fluidRow(
uiOutput("result")
)
)
}
server <- function(input, output, session) {
callModule(addRmBtnServer, id = 1,
serverModToCall = 'firstServer',
uiModToCall = 'firstUI')
res <- reactive({ })
output$result <- renderUI({
verbatimTextOutput(paste0(input[[NS(1, "select")]]), placeholder = T)
})
}
shinyApp(ui = ui, server = server)
It seems there were somme errors in the code
First, the call to firstServer was
callModule(do.call(firstServer, args = list(id = params$btn)))
which translates to
callModule(firstServer(params$btn))
callModule should however be invoked like this:
callModule(firstServer, params$btn)
The version below passes functions rather than function names, so the differences might be hard to spot at first glance.
Second, you need to namespace the ids for insertUI/removeUI. You can read more about this in the "nesting modules" section of this article.
## in addRmBtnServer/observe add button
insertUI(
selector = paste('#', ns('placeholder')),
ui = uiModToCall(ns(params$btn))
)
## in addRmBtnServer/observe remove button
removeFirstUI(ns(params$btn))
## in global scope
removeFirstUI <- function(id){
removeUI(selector = paste0('#', NS(id, "first") ))
}
Third, i am not sure what output$result was supposed to show, so I omitted it in the version below.
library(shiny)
firstUI <- function(id){uiOutput(NS(id, "first"))}
firstServer <- function(input, output, session){
output$first <- renderUI({
selectInput(session$ns("select"), h4("Select"), letters[1:4])
})
}
removeFirstUI <- function(id){
removeUI(selector = paste0('#', NS(id, "first")))
}
addRmBtnUI <- function(id) {
ns <- NS(id)
tags$div(
actionButton(inputId = ns('insertParamBtn'), label = "Add"),
actionButton(ns('removeParamBtn'), label = "Remove"),
hr(),
tags$div(id = ns('placeholder'))
)
}
addRmBtnServer <- function(input, output, session, moduleToReplicate) {
ns = session$ns
params <- reactiveValues(btn = 0)
observeEvent(input$insertParamBtn, {
params$btn <- params$btn + 1
callModule(moduleToReplicate$server, id = params$btn)
insertUI(
selector = paste0('#', ns('placeholder')),
ui = moduleToReplicate$ui(ns(params$btn))
)
})
observeEvent(input$removeParamBtn, {
moduleToReplicate$remover(ns(params$btn))
params$btn <- params$btn - 1
})
}
ui <- fluidPage(addRmBtnUI("addRm"))
server <- function(input, output, session) {
callModule(
addRmBtnServer, id = "addRm",
moduleToReplicate = list(
ui = firstUI,
server = firstServer,
remover = removeFirstUI
)
)
}
shinyApp(ui = ui, server = server)

Resources