1

Using this answer, I made a DT::datatable in Shiny which contain a column of checkboxes, but I'm having an issue where if I check some boxes, go to another page on the table, then return to the original page, the boxes are now unchecked. How can I make the box-checking persistent when switching pages? Here's a minimal example:

library(shiny)
library(DT)
runApp(
  list(ui = fluidPage(
    dataTableOutput("dtout")),
    server = function(input, output, session) {
      
      shinyInput <- function(FUN, id, num, ...) {
        inputs <- character(num)
        for (i in seq_len(num)) {
          inputs[i] <- as.character(FUN(paste0(id, i), label = NULL, ...))
        }
        inputs
      }
      
      output$dtout <- renderDataTable({
        datatable(
          cbind(Pick = shinyInput(checkboxInput, "srows_", nrow(mtcars), value = NULL, width = 1), mtcars),
          options = list(drawCallback= JS('function(settings) {Shiny.bindAll(this.api().table().node());}')),
          selection = 'none', escape = F)
      })
    })
)
saheed
  • 340
  • 2
  • 12
  • In case this helps, {reactable} has a similar feature inbuilt for selecting rows. https://glin.github.io/reactable/articles/examples.html#select-on-click – Mwavu Jul 16 '23 at 10:33

2 Answers2

0

In order to keep the checkbox state while moving between pages, you have to disable server side processing. You can set this by calling DT::renderDataTable with server = FALSE.

enter image description here

Complete minimal example:

library(shiny)
library(DT)
runApp(list(
    ui = fluidPage(dataTableOutput("dtout")),
    server = function(input, output, session) {
        shinyInput <- function(FUN, id, num, ...) {
            inputs <- character(num)
            for (i in seq_len(num)) {
                inputs[i] <- as.character(FUN(paste0(id, i), label = NULL, ...))
            }
            inputs
        }
        
        output$dtout <- renderDataTable({
            datatable(
                cbind(
                    Pick = shinyInput(
                        checkboxInput,
                        "srows_",
                        nrow(mtcars),
                        value = NULL,
                        width = 1
                    ),
                    mtcars
                ),
                options = list(
                    drawCallback = JS(
                        'function(settings) {Shiny.bindAll(this.api().table().node());}'
                    )
                ),
                selection = 'none',
                escape = F
            )
        }, server = FALSE)
    }
))
Jan
  • 2,245
  • 1
  • 2
  • 16
-5

To make the checkbox state persistent when switching pages in an R Shiny DataTable, you can use server-side processing and handle the checkbox input separately from the DataTable itself. Here's an updated version of your code that demonstrates this:

library(shiny)
library(DT)

runApp(
  list(ui = fluidPage(
    dataTableOutput("dtout")),
    server = function(input, output, session) {
      
      shinyInput <- function(FUN, id, num, values = NULL, ...) {
        inputs <- character(num)
        for (i in seq_len(num)) {
          inputs[i] <- as.character(FUN(paste0(id, i), label = NULL, value = values[i], ...))
        }
        inputs
      }
      
      # Store checkbox values in a reactiveValues object
      checkboxValues <- reactiveValues(values = rep(FALSE, nrow(mtcars)))
      
      observe({
        # Update checkbox values when checkboxes are changed
        for (i in seq_along(checkboxValues$values)) {
          checkboxId <- paste0("srows_", i)
          checkboxValues$values[i] <- input[[checkboxId]]
        }
      })
      
      output$dtout <- renderDataTable({
        # Add a column for checkboxes dynamically based on checkboxValues$values
        datatable(
          cbind(Pick = shinyInput(checkboxInput, "srows_", nrow(mtcars), values = checkboxValues$values, width = 1), mtcars),
          options = list(
            drawCallback = JS('function(settings) {Shiny.unbindAll(this.api().table().node()); Shiny.bindAll(this.api().table().node());}'),
            serverSide = TRUE # Enable server-side processing
          ),
          selection = 'none', escape = FALSE
        )
      }, server = TRUE) # Set server = TRUE to enable server-side processing
      
      # Update checkbox values when the table is re-rendered
      observeEvent(input$dtout_state_change$page, {
        selectedRows <- input$dtout_rows_selected
        if (!is.null(selectedRows)) {
          for (i in seq_along(checkboxValues$values)) {
            checkboxValues$values[i] <- i %in% selectedRows
          }
        }
      })
      
    })
)

In this modified code:

  1. We store the checkbox values in a reactiveValues object called checkboxValues. This allows us to keep track of the state of each checkbox.

  2. We use an observer to update the checkboxValues when any checkbox is changed. This ensures that the values are always up to date.

  3. In the renderDataTable function, we dynamically generate the checkboxes using the shinyInput function. We pass in the values argument to initialize the checkboxes with the stored values from checkboxValues.

  4. We enable server-side processing by setting serverSide = TRUE in the datatable options. This allows the DataTable to handle pagination and other operations efficiently.

  5. We use an observer to update the checkboxValues whenever the table is re-rendered. This ensures that the checkbox values stay persistent even when switching pages.

With these modifications, the checkbox state should now persist when switching pages in the DataTable.

Let me know if you have any further questions!

wb-ts
  • 1
  • 1