5

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)

1 Answers1

3

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.

Ben
  • 28,684
  • 5
  • 23
  • 45
  • It works, thanks! If I want to include more options inside the renderDataTable what should I do? – Jose Luis May 19 '21 at 07:12
  • 1
    @JoseLuis Great - glad to hear. See my edited answer that describes two ways to approach this. – Ben May 19 '21 at 12:56