Passing same reactive object to the same shiny module causes "Error: promise already under evaluation"

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)

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.