Objective: I have created a simple reproducible app in which I am attempting to add UI components through an action button so that I can filter the same dataset by the UI filters generated from the action button. I am attempting to use the shiny module code to save the dataset after the filter is applied to it and reuse the filtered dataset the next time the actionbutton is clicked. In other words, I want to reuse this filtered dataset (not the original unfiltered dataset) everytime a new set of UI components are generated by clicking the actionbutton.
Problem: The desired outcome works for the first instance when the user clicks the actiobutton, but any sequential click of the actionbutton results in Error: promise already under evaluation: recursive default argument reference or earlier problems? Is what I am attempting to do not possible in shiny / shiny modules, or am I performing something incorrectly? Any help would be greatly appreciated.
library(shiny)
library(dplyr)
add.filter.UI = function(id) {
ns = NS(id)
fluidRow(
column(4, uiOutput(ns("UI_1"))),
column(6, uiOutput(ns("UI_2"))),
column(width = 2,
actionButton(inputId = ns("rm.filter"), label = "Filter", icon = icon("minus"), style = "position: relative; bottom: 0; right:0; top:24px;")),
br(),
column(width = 12, tableOutput(ns("test"))))
}
add.filter.server = function(id, data) {
moduleServer(id, function(input, output, session) {
ns = session$ns
output$UI_1 <- renderUI({
selectInput(inputId = ns("sel.col"),
label = "Select a column",
choices = names(data %>% select_if(is.numeric)),
multiple = F)
})
col.rng = reactive({ data %>% select(one_of(input$sel.col)) })
output$UI_2 = renderUI({
sliderInput(inputId = ns("sel.rng"),
label = "Filter the range",
min = min(col.rng(), na.rm = T),
max = max(col.rng(), na.rm = T),
value = c(min(col.rng(), na.rm = T), max(col.rng(), na.rm = T)),
step = (max(col.rng(), na.rm = T) - min(col.rng(), na.rm = T)) / 100 # of breaks
)
})
data.filtered = reactive({
data %>%
rename(Var = one_of(input$sel.col)) %>%
arrange(Var) %>%
filter(Var >= min(input$sel.rng), Var <= max(input$sel.rng)) %>%
rename(!!input$sel.col := Var)
})
output$test = renderTable({
data.filtered() %>%
head()
})
return( data.filtered )
})
}
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
column(width = 2, offset = 10, actionButton(inputId = "add.filter", label = "Filter", icon = icon("plus"), style = "position:relative; left:10px;")),
tags$div(id = 'placeholder')
),
mainPanel(
tableOutput(outputId = "tbl")
)
)
)
server <- function(input, output, session) {
counter = reactiveVal(value = 0)
observeEvent(input$add.filter, {
id <- paste0("#filter_", input$add.filter) # - 1, "-break"
insertUI(selector = "#placeholder",
where = "afterEnd",
ui = tags$div(
add.filter.UI(paste0("filter_", input$add.filter)),
id = id)
)
counter(input$add.filter)
if (counter() == 1) {
df.filtered = add.filter.server(id = paste0("filter_", input$add.filter), data = mtcars)
} else {
df.filtered = add.filter.server(id = paste0("filter_", input$add.filter), data = df.filtered())
}
output$tbl = renderTable({
df.filtered()
})
})
}
# Run the app ----
shinyApp(ui = ui, server = server)