Capture filtered results from a datatable and store it as a new dataset in Shiny

I have a shiny application that loads a couple of datasets (diamonds & mtcars) and displays them as datatable in the mainpanel. I am trying to implement a couple of functionality

  1. Store datasets: Once the user create filters in the datatable, allow them to store the filtered results as a new dataset
  2. Remove datasets: Allow the users to remove any datasets from the list of created datasets

app.R

library(shiny)
library(shinyWidgets)
library(dplyr)
library(tidyverse)
library(shinyjs)


ui <- fluidPage(
  titlePanel("Dataset Tool"),
  sidebarLayout(
    sidebarPanel(width = 3,
                 conditionalPanel(
                   condition = "input.tabs=='Datasets'",
                   uiOutput("ui_datasets"),
                   uiOutput("ui_storedataset"),
                   br(), br(),
                   wellPanel(
                     checkboxInput("data_remove", "Remove dataset from memory", 
                                   FALSE),
                     conditionalPanel(
                       condition = "input.data_remove == true",
                       uiOutput("ui_removedataset"),
                       actionButton("removeDataSetButton", 
                                    "Remove dataset")
                     )
                   )
                 )
                 
    ),
    mainPanel(
      tabsetPanel(id = "tabs",
                  tabPanel("Datasets",
                           DT::dataTableOutput("datatable")
                  )
      )
    )
  )
)


server = function(input, output,session) {

  my_data <- new.env()
  my_state <- list()
  my_info <- reactiveValues()
  datasetlist <- c()
  my_df <- list()
  df <- list()
  
  df_names <- c("diamonds", "mtcars")
  for (j in df_names) {
    df[[j]] <- get(j)
    datasetlist <- c(datasetlist, j)
  }
  my_info[["datasetlist"]] <- datasetlist
  my_df[["df"]] <- df

  output$ui_datasets <- renderUI({
    tagList(
      selectInput(
        inputId = "dataset",
        label = "Datasets:",
        choices = my_info[["datasetlist"]],
        multiple = FALSE
      )
    )
  })
  
  output$ui_storedataset <- renderUI({
    tagList(
      wellPanel(
        tags$table(
          tags$td(textInput("stored_name", 
                            "Store new dataset as:", 
                            "", 
                            placeholder = "name of the dataset")),
          tags$td(actionButton("view_store", 
                               "Store"), 
                  style = "padding-right:30px;")
        )
      )
    )
  })
  
  observeEvent(input$datatable_search_columns, {
    my_state$datatable_search_columns <<- input$datatable_search_columns
  })
  
  observeEvent(input$datatable_state, {
    my_state$datatable_state <<-
      if (is.null(input$datatable_state)) list() else input$datatable_state
  })
  
  output$datatable <- DT::renderDataTable({
    dat <- df[[(input$dataset)]]
    
    search <- my_state$datatable_state$search$search
    if (is.null(search)) search <- ""
    fbox <- if (nrow(dat) > 5e6) "none" else list(position = "top")
    

    DT::datatable(
      dat,
      filter = fbox,
      selection = "none",
      rownames = FALSE,
      fillContainer = FALSE,
      escape = FALSE,
      style = "bootstrap",
      options = list(
        stateSave = TRUE, 
        searchCols = lapply(my_state$datatable_search_columns, function(x) list(search = x)),
        search = list(search = search, regex = TRUE),
        order = {
          if (is.null(my_state$datatable_state$order)) {
            list()
          } else {
            my_state$datatable_state$order
          }
        },
        columnDefs = list(
          list(orderSequence = c("desc", "asc"), targets = "_all"),
          list(className = "dt-center", targets = "_all")
        ),
        autoWidth = TRUE,
        processing = isTRUE(fbox == "none"),
        pageLength = {
          if (is.null(my_state$datatable_state$length)) 10 else my_state$datatable_state$length
        },
        lengthMenu = list(c(5, 10, 25, 50, -1), c("5", "10", "25", "50", "All"))
      ),
      callback = DT::JS('$(window).on("unload", function() { table.state.clear(); })')
    )
  })
  
  observeEvent(input$view_store, {
    req(input$stored_name)
    dataset <- (input$stored_name)
    if (input$stored_name != dataset) {
      updateTextInput(session, inputId = "stored_name", value = dataset)
    }
    
    my_data[[dataset]] <- get(input$dataset)
    updateSelectInput(session = session, inputId = "dataset", 
                      selected = input$dataset)
  })
  
  output$ui_removedataset <- renderUI({
    selectInput(
      inputId = "removeDataset",
      label = NULL,
      choices = my_info[["datasetlist"]],
      selected = NULL,
      multiple = TRUE,
      size = length(my_info[["datasetlist"]]),
      selectize = FALSE
    )
  })
  
  observeEvent(input$removeDataSetButton, {
    if (is.null(input$removeDataset)) return()
    datasets <- my_info[["datasetlist"]]
    if (length(datasets) > 1) { 
      removeDataset <- input$removeDataset
      if (length(datasets) == length(removeDataset)) {
        removeDataset <- removeDataset[-1]
      }
      suppressWarnings(rm(list = removeDataset, envir = my_data))
      my_info[["datasetlist"]] <- datasets[-which(datasets %in% removeDataset)]
    }
  })
  
}

shinyApp(ui = ui, server = server)

I think the "removedatasets" functionality works fine. I am not able to get the "store dataset" functionality to work. I am not sure how to capture the filtered datatable from the environment to store and add it to the list of datasets.

I would really appreciate any help on this. Thanks.

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.