Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sort multiple tables in Shiny

Is there any way to sort a column in a table and the same column in another table? For example, in the code below I draw two datatables with mtcars data and I would like to sort the column mpg of the first table by clicking, showing the same sorting in the second table automatically, the same if I click on the second table, automatically sorting the first table.

library(DT)
library(shiny)

ui <- basicPage(
  h2("The mtcars data"),
  dataTableOutput("mytable"),
  br(),
  dataTableOutput("mytable2")
)

server <- function(input, output) {
  output$mytable = DT::renderDataTable({
    mtcars
  })
  output$mytable2 = DT::renderDataTable({
    mtcars
  })
}

shinyApp(ui, server)
like image 362
Jose Luis Avatar asked Oct 14 '22 21:10

Jose Luis


1 Answers

I tried using stateSave option with datatable and believe this might be helpful. The order option can be saved in reactiveValues and be updated when the order of either table changes. Before changing the reactiveValues, I make sure it is a change in order from what is stored, otherwise you may have duplicate updates of the datatable. Finally, because the state would be saved in localStorage, adding stateDuration = -1 will prevent additional ordering when the user accesses the app again.

server <- function(input, output, session) {
  
  rv <- reactiveValues(
    options = list(stateSave = TRUE,
                   stateDuration = -1,
                   order = list())
  )
  
  output$mytable = DT::renderDataTable({
    datatable(mtcars, options = rv$options)
  })
  
  output$mytable2 = DT::renderDataTable({
    datatable(mtcars, options = rv$options)
  })
  
  observeEvent(input$mytable_state$order, {
    if (!identical(rv$options$order, input$mytable_state$order)) {
      rv$options$order <- input$mytable_state$order
    }
  })
  
  observeEvent(input$mytable2_state$order, {
    if (!identical(rv$options$order, input$mytable2_state$order)) {
      rv$options$order <- input$mytable2_state$order
    }
  })
  
}

Edit: With regards to adding additional options, you would have different ways you could go about this.

First, you could add more options to rv (e.g., add pageLength):

rv <- reactiveValues(
    options = list(stateSave = TRUE,
                   stateDuration = -1,
                   pageLength = 5,
                   order = list())
)

Alternatively, if you want to add the options inside of datatable, and maybe use different options between the two tables, you could instead store the order in rv:

server <- function(input, output, session) {
  
  rv <- reactiveValues(
    order = list()
  )
  
  output$mytable = DT::renderDataTable({
    datatable(mtcars, options = list(
      stateSave = TRUE,
      stateDuration = -1,
      order = rv$order))
  })
  
  output$mytable2 = DT::renderDataTable({
    datatable(mtcars, options = list(
      stateSave = TRUE,
      stateDuration = -1,
      order = rv$order))
  })
  
  observeEvent(input$mytable_state$order, {
    if (!identical(rv$order, input$mytable_state$order)) {
      rv$order <- input$mytable_state$order
    }
  })
  
  observeEvent(input$mytable2_state$order, {
    if (!identical(rv$order, input$mytable2_state$order)) {
      rv$order <- input$mytable2_state$order
    }
  })
  
}

In this case, rv$order will store the table order only, and not all of the options.

like image 197
Ben Avatar answered Oct 21 '22 00:10

Ben