javascriptrshinydt

Keep column filters after rerendering the table


I have a datatable that uses both interactive shiny filters via action buttons which subset my data, and also the built in datatable filters. The action buttons perform bulk filtering by subsetting the dataframe. The problem I'm having is that whenever one of these bulk filters is applied, the datatable is re-rendered and all the individual column filters are cleared. I'd like to be able to keep the individual column filters active whenever the data is subsetted and the table re-rendered.

I've managed to find that I can output and isolate this information from the datatable using input$mytable_search_columns but I have no idea how to write that javascript that will apply this criteria upon re-rendering the table.

library(shinyBS)
library(DT)

server <- function(input, output, session) {

  df <- reactive({iris})
  
  df.sub <- reactive({
    if(input$buttonfilter == 0){
      df.sub <- df()
    }
    if(input$buttonfilter == 1){
      df.sub <- subset(df(), subset = Species == 'setosa')
    }
    df.sub
  })
  
  output$mytable <- DT::renderDataTable(df.sub(),
                                        filter = 'top')
  output$filters <- renderText({input$mytable_search_columns})
}
ui <- fluidPage(
  h3('Button Toggle Filter'),
  bsButton("buttonfilter","Show only Setosa", type = 'toggle'),
  br(),
  br(),
  h3('Current filters'),
  textOutput('filters'),
  br(),
  br(),
  DT::dataTableOutput('mytable')
  
  
  
)

shinyApp(ui = ui, server = server)

What I'm trying to do is find a way to maintain the current DT filters when the table is re-rendered based on the subset initiated by the action button. In this example you can see the filters are cleared once the table is re-rendered.


Solution

  • I found a way without using JavaScript. I think this is what you want:

    library(shinyBS)
    library(DT)
    
    server <- function(input, output, session) {
      
      df <- reactive({
        if(input$buttonfilter %% 2 == 0){
          df.sub <- iris
        } else {
          df.sub <- subset(iris, subset = Species == 'setosa')
        }
        df.sub
      })
      
    
      output$mytable <- DT::renderDataTable(isolate(df()), filter = 'top')
      proxy <- dataTableProxy('mytable')
      
      observe({
        replaceData(proxy, df(), resetPaging = FALSE)
      })  
    }
    
    ui <- fluidPage(h3('Button Toggle Filter'),
                    bsButton("buttonfilter","Show only Setosa", type = 'toggle'),
                    br(),br(),
                    DT::dataTableOutput('mytable')
    )
    
    shiny::shinyApp(ui=ui,server=server)
    

    We basically create a proxy for our table and just replace the data for the rendered table. For details check the very bottom of this page: https://rstudio.github.io/DT/shiny.html

    I did not find the example mentioned there on my computer but you can go to GitHub and copy and paste it: https://github.com/rstudio/DT/blob/master/inst/examples/DT-reload/app.R