I have a checkbox and a table in my code. What I want is when user check certain box, new column with corresponding name with be generated.
Ideal Case Example:
However, this is what I have with my code:
Here is my code:
lineGraphUI <- function(id) {
ns <- NS(id)
tags$div(
checkboxGroupInput(ns("variable"), "Variables to show:",
c("black" = "black",
"white" = "white",
"asian" = "asian")),
tableOutput(ns("datatbr"))
)
}
lineGraph <- function(input, output, session) {
da <- read.csv(file = "RaceByYearTemplet.csv", header = TRUE)
output$datatbr <- renderTable({
da[c("year",input$variable), drop = FALSE]
}, rownames = TRUE)
}
navBlockUI <- function(id) {
ns <- NS(id)
tags$div(
tags$div(class = "tabPanel-plotBlock",
tabsetPanel(type = "tabs",
tabPanel("Graph", lineGraphUI(ns("line"))),
tabPanel("Line", tablePlotUI(ns("table")))
)
)
)
}
navBlock <- function(input, output, session) {
callModule(lineGraph, "line")
callModule(tablePlot, "table")
}
I think the problem might shiny module can not be update when the checkbox is checked? Because I have tried to put the same code directly in app.R and it works just fine(as it shows in the 'ideal case example' image above).
This works like this:
lineGraphUI <- function(id) {
ns <- NS(id)
tags$div(
checkboxGroupInput(ns("variable"), "Variables to show:",
c("black" = "black",
"white" = "white",
"asian" = "asian")),
tableOutput(ns("datatbr"))
)
}
lineGraph <- function(input, output, session) {
da <- iris[1:5,]
names(da) <- c("black", "white", "asian", "abcd", "year")
output$datatbr <- renderTable({
da[, c("year",input$variable), drop = FALSE]
}, rownames = TRUE)
}
navBlockUI <- function(id) {
ns <- NS(id)
tags$div(
tags$div(class = "tabPanel-plotBlock",
tabsetPanel(type = "tabs",
tabPanel("Graph", lineGraphUI(ns("line")))
)
)
)
}
ui <- fluidPage(
navBlockUI("xxx")
)
navBlock <- function(input, output, session) {
callModule(lineGraph, "xxx-line")
}
shinyApp(ui, navBlock)
Related
I'm creating a shiny module, where I wish to display some pop-up messages to the user via shinyalerts and include dropdown menus via htlm = TRUE and shinyWidgets::pickerInput. For each shinyalert the options should be different and the alerts should appear right after each other when the user has selected the relevant option.
However, when running the shinyalerts within a for loop, only the first alert shows the drop-down, the following does not. Please have a look at the example below and screenshots. Any ideas what I'm doing wrong?
Module UI:
mod_match_columns_ui <- function(id){
ns <- NS(id)
tagList(
shinyalert::useShinyalert(),
actionButton(ns("run"), label = "Start!")
)
}
Module server:
mod_match_columns_server <- function(input, output, session){
ns <- session$ns
options <- list(c("option_1","option_2"),
c("option_3","option_4"))
observeEvent(input$run, {
for(col in 1:2){
nms <- options[[i]]
output[[paste0("dropdown",col)]] <- renderUI({
shinyWidgets::pickerInput(
inputId = ns(paste0("options",col)),
label = "Options listed below",
choices = nms,
selected = "",
multiple = FALSE,
options = shinyWidgets::pickerOptions(size = 15)
)
})
shinyalert::shinyalert(
title = "Pick an option!",
html = TRUE,
text = tagList(
uiOutput(ns(paste0("dropdown", col)))
),
inputId = ns(paste0("modal", col))
)
}
})
}
Run module:
library(shiny)
ui <- fluidPage(
mod_match_columns_ui("match_columns_ui_1")
)
server <- function(input, output, session) {
callModule(mod_match_columns_server, "match_columns_ui_1")
}
shinyApp(ui = ui, server = server)
First iteration:
Second iteration:
Why is the dropdown not shown in the second iteration?? Thanks
Try this
library(shiny)
library(shinyalert)
mod_match_columns_ui <- function(id){
ns <- NS(id)
tagList(
shinyalert::useShinyalert(),
actionButton(ns("run"), label = "Start!")
)
}
mod_match_columns_server <- function(id) {
moduleServer(id,
function(input, output, session) {
ns <- session$ns
options <- list(c("option_1","option_2"),
c("option_3","option_4"))
lapply(1:2, function(col){
output[[paste0("dropdown",col)]] <- renderUI({
shinyWidgets::pickerInput(
inputId = ns(paste0("options",col)),
label = paste("Options",col,"listed below"),
choices = options[[col]],
selected = "",
multiple = FALSE,
options = shinyWidgets::pickerOptions(size = 15)
)
})
})
observeEvent(input$run, {
shinyalert::shinyalert(
title = "Pick an option!",
html = TRUE,
text = tagList(
lapply(1:2, function(i){uiOutput(ns(paste0("dropdown",i)))})
)
# callbackR = function(x) { message("Hello ", x) },
# inputId = ns(paste0("modal"))
)
})
observe({
print(input$options1)
print(input$options2)
print(input$shinyalert)
})
})
}
ui <- fluidPage(
tagList(
mod_match_columns_ui("match_columns_ui_1")
)
)
server <- function(input, output, session) {
mod_match_columns_server("match_columns_ui_1")
}
shinyApp(ui = ui, server = server)
I have a shiny module and I'm having a huge issue getting it to work. I'm trying to create a dashboard with multiple tabs and am exploring modules to reduce the amount of duplication.
I can get the application to work if I hardcode the server explicitly with the code but when I create modules for the server part it doesn't won't work. I would really appreciate any help as I have tried looking everywhere for a workable example, Below is a reproducible example of a proportion of the code that I would like to modulize,
datasetInput <- function(id, Taxhead = NULL) {
ns <- NS(id)
names <- colnames(mtcars)
if (!is.null(Taxhead)) {
pattern <- paste0(Taxhead)
names <-names$name[sapply(names, function(x){ grepl(pattern,x, ignore.case = TRUE)})] #### filter for a match
}
selectInput(ns("dataset"), "Pick a Report", choices = names)
}
#### Server 1
#### Collect the data set based on the selection in datasetInput
datasetServer <- function(id) {
moduleServer(id, function(input, output, session) {
#### Outputs the data set
#### reactive( read.csv(paste0("Data/",input$dataset,".csv")) )
reactive( mtcars )
})}
#### Display the variables of interest
selectVarInput <- function(id){
ns <- NS(id)
tagList(
selectInput(ns("var"), "Select grouping Variables", choices = NULL, multiple = TRUE) ,
selectInput(ns("var2"), "Select Measure Variables", choices = NULL, multiple = TRUE)
) }
##### Server 2
#### Returns the data as a reactive
selectVarServer <- function(id, data) {
find_vars <- function(data, filter) { names(data)}
moduleServer(id, function(input, output, session) {
observeEvent(data(), {
updateSelectInput(session, "var", choices = find_vars(data()))
})
observeEvent(data(), {
updateSelectInput(session, "var2", choices = find_vars(data()))
})
reactive(data() %>% group_by(across(all_of(input$var))) %>% summarise(across(all_of(input$var2),sum), n = n()))
})}
selectDataVarUI <- function(id, Taxhead =NULL) {
ns <- NS(id)
tagList(
datasetInput(ns("data"), Taxhead ),
selectVarInput(ns("var"))
)}
#### Server 3
selectDataVarServer <- function(id) {
moduleServer(id, function(input, output, session) {
data <- datasetServer("data")
var <- selectVarServer("var", data)
var })}
Date_Range_UI <- function(id) {
ns <- NS(id)
# Sidebar to demonstrate various slider options ----
tagList(
# Sidebar with a slider input
# # Select form input for checking
radioButtons(ns("Period"),
label = "Select Desired Comparison Period",
choices = c( "Daily", "Monthly","Yearly"),
selected = "Monthly")
,
# Only show this panel if Monthly or Quarterly is selected
conditionalPanel(
condition = "input.Period != 'Yearly'", ns = ns,
dateRangeInput(ns('dateRange'),
label = 'Date range input',
start = Sys.Date()-180,
end = Sys.Date() ,
min = NULL, max = Sys.Date() ,
separator = " - ", format = "MM-yyyy",
startview = 'year', language = 'en', weekstart = 0,autoclose = TRUE))
,
# Only show this panel if Custom is selected
conditionalPanel(
condition = "input.Period == 'Yearly'", ns = ns,
sliderInput(ns("yearly"), "Years", min = 2000, max = as.integer(format(Sys.Date(),"%Y")), value = c(2008,2021), round = TRUE,step = 1)),
) ### close side bar layout
### close fluid page layout
}
Date_Range_Server <- function(id ) {
moduleServer(id,
function(input, output, session) {
x <- reactive({input$Period})
return(
list(
Startdate = reactive(if(x() == "Yearly") {input$yearly[1]
}
else if(x() == "Monthly") {
as.integer(format(input$dateRange[1],"%Y%m"))
}else{
as.integer(format(input$dateRange[1],"%Y%m%d"))})
,
Enddate = reactive(if(x() == "Yearly") {input$yearly[2]
}
else if(x() == "Monthly") {
as.integer(format(input$dateRange[2],"%Y%m"))
}else{
as.integer(format(input$dateRange[2],"%Y%m%d"))})
,
Choice = reactive(input$Period )))
})}
###### this won't work!
betting_UI <- function(id) {
ns <- NS(id)
sidebarLayout(
sidebarPanel(
Date_Range_UI("data_range"),
selectDataVarUI(id = "var", Taxhead =NULL)),
mainPanel(
tableOutput(ns("table")),
verbatimTextOutput (ns("test"))
)) }
Betting_Server <- function(input, output, session) {
date_range <- Date_Range_Server("data_range")
output$test <- renderPrint( date_range$Startdate())
output$table <- renderTable(var(), width = 40)
}
ui <- fluidPage(
betting_UI("betting")
)
server <- function(input, output, session) {
Betting_Server("betting")
}
shinyApp(ui, server)**
##### this works fine I thought putting the modules into the server would work as above?????
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
Date_Range_UI("data_range"),
selectDataVarUI(id = "var", Taxhead =NULL)),
mainPanel(
tableOutput("table"),
verbatimTextOutput ("test")
)) )
#### Server
server <- function(input, output, session) {
var <- selectDataVarServer("var")
date_range <- Date_Range_Server("data_range")
output$test <- renderPrint( date_range$Startdate())
output$table <- renderTable(var(), width = 40)
}
shinyApp(ui, server)
You have to use ns() in your module UI
betting_UI <- function(id) {
ns <- NS(id)
sidebarLayout(
sidebarPanel(
Date_Range_UI(ns("data_range")),
selectDataVarUI(id = ns("var"), Taxhead = NULL)
),
mainPanel(tableOutput(ns("table")),
verbatimTextOutput (ns("test")))
)
}
You also have to use moduleServer() to create the module server
Betting_Server <- function(id) {
moduleServer(id,
function(input, output, session) {
var <- selectDataVarServer("var")
date_range <- Date_Range_Server("data_range")
output$test <- renderPrint(date_range$Startdate())
output$table <- renderTable(var(), width = 40)
})
}
Background
The application is of the following structure:
.
├── R
│ ├── mod_observationSelector.R
│ ├── mod_previewTable.R
│ └── mod_summaryTable.R
└── app.R
With the files fulling the respective functions:
mod_observationSelector.R - provides an updateSelectInput mechanism facilitating selction of integere or real columns in mtcars data
mod_previewTable.R - generates head for selected column
mod_summaryTable.R - generates summary for selected column
Design assumptions
mod_observationSelector.R linked interface elements available in this module should be usable across remaining modules providing a selection mechanism
Problem
After nesting, the drop-down selection does no longer update.
Working version
Prior to nesting.
mod_observationSelector.R
observationSelectorUI <- function(id) {
ns <- NS(id)
fluidPage(
selectInput(
inputId = ns("varTypes"),
label = h3("Variable types"),
choices = list("Integer" = TRUE,
"Real" = FALSE),
selectize = FALSE,
multiple = FALSE
),
selectInput(
inputId = ns("selectColumn"),
label = h4("Selected Column"),
choices = character(0)
)
)
}
observationSelectorServer <- function(id, data) {
moduleServer(id,
function(input, output, session) {
observeEvent(eventExpr = input$varTypes,
handlerExpr = {
all_cols <- map_lgl(.x = mtcars, ~ all(. %% 1 == 0))
selected_cols <-
names(all_cols[all_cols == input$varTypes])
updateSelectInput(
session = session,
inputId = "selectColumn",
label = paste(
"Selected",
ifelse(input$varTypes, "integer", "real"),
"columns"
),
choices = selected_cols
)
})
})
}
app.R
library("shiny")
library("tidyverse")
ui <- fluidPage(
titlePanel("Nested Modules"),
observationSelectorUI("colChooser")
)
# Define server logic required to draw a histogram
server <- function(input, output) {
observationSelectorServer("colChooser")
}
# Run the application
shinyApp(ui = ui, server = server)
Broken version
Problems
Previously working updateSelect is now broken
app.R
library("shiny")
library("tidyverse")
ui <- fluidPage(titlePanel("Nested Modules"),
tabsetPanel(summaryUI("modSummary"),
previewUI("modPreview")
))
# Define server logic required to draw a histogram
server <- function(input, output) {
summaryServer("modSummary")
previewServer("modPreview")
}
# Run the application
shinyApp(ui = ui, server = server)
mod_observationSelector.R
In effect, no change.
observationSelectorUI <- function(id) {
ns <- NS(id)
fluidPage(
selectInput(
inputId = ns("varTypes"),
label = h3("Variable types"),
choices = list("Integer" = TRUE,
"Real" = FALSE),
selectize = FALSE,
multiple = FALSE
),
selectInput(
inputId = ns("selectColumn"),
label = h4("Selected Column"),
choices = character(0)
)
)
}
observationSelectorServer <- function(id, data) {
moduleServer(id,
function(input, output, session) {
observeEvent(eventExpr = input$varTypes,
handlerExpr = {
all_cols <- map_lgl(.x = mtcars, ~ all(. %% 1 == 0))
selected_cols <-
names(all_cols[all_cols == input$varTypes])
updateSelectInput(
session = session,
inputId = "selectColumn",
label = paste(
"Selected",
ifelse(input$varTypes, "integer", "real"),
"columns"
),
choices = selected_cols
)
})
})
}
mod_summaryTable.R
summaryUI <- function(id) {
ns <- NS(id)
tabPanel("Summary table",
column(4, observationSelectorUI(ns("colChooser"))),
column(8, tableOutput(ns('summaryTable'))))
}
summaryServer <- function(id) {
moduleServer(id,
function(input, output, session) {
output$summaryTable <-
renderTable(summary(mtcars[, input$selectColumn]))
})
}
mod_previewTable
previewUI <- function(id) {
ns <- NS(id)
tabPanel("Summary table",
column(4, observationSelectorUI(ns("colChooser"))),
column(8, tableOutput(ns('headTable'))))
}
previewServer <- function(id) {
moduleServer(id,
function(input, output, session) {
output$headTable <-
renderTable(head(mtcars[, input$selectColumn]))
})
}
Desired outcomes
Drop-down selection updates across the modules
Results from the in-module drop-down selection can be used in "outer" module to produce summaries, etc.
For convenience, the code is also available on GitHub: konradzdeb/nestedModule.
For posterity, the solution is as follows
mod_observationSelector.R
Reactive element is returned.
observationSelectorUI <- function(id) {
ns <- NS(id)
tagList(
selectInput(
inputId = ns("varTypes"),
label = h3("Variable types"),
choices = list("Integer" = TRUE,
"Real" = FALSE),
selectize = FALSE,
multiple = FALSE
),
selectInput(
inputId = ns("selectColumn"),
label = h4("Selected Column"),
choices = c("cyl", "hp", "vs", "am", "gear", "carb")
)
)
}
observationSelectorServer <- function(id, data) {
moduleServer(id,
function(input, output, session) {
observeEvent(eventExpr = input$varTypes,
handlerExpr = {
all_cols <- map_lgl(.x = mtcars, ~ all(. %% 1 == 0))
selected_cols <-
names(all_cols[all_cols == input$varTypes])
updateSelectInput(
session = session,
inputId = "selectColumn",
label = paste(
"Selected",
ifelse(input$varTypes, "integer", "real"),
"columns"
),
choices = selected_cols
)
})
# Return the selection result
return(reactive({
validate(need(input$selectColumn, FALSE))
input$selectColumn
}))
})
}
Using module inputs
As with any other reactive, I'm bringing the results from the nested module and then call them innerResult().
previewUI <- function(id) {
ns <- NS(id)
tabPanel("Summary table",
column(4, observationSelectorUI(ns("colChooser"))),
column(8, tableOutput(ns('headTable'))))
}
previewServer <- function(id) {
moduleServer(id,
function(input, output, session) {
innerResult <- observationSelectorServer("colChooser")
output$headTable <- renderTable(head(mtcars[, innerResult()]))
})
}
Full app
Available on GitHub: b25758b.
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)
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)