Switching to different DataTable page when input change in Shiny?

Viewed 139

Basically, I want the output DataTable to switch to the page that has the values matching with the Input selection value (radioButtons). I know I can do a simple filter but that would remove all the other rows that do not match the criteria which I do not want.

Any help is appreciated! Thanks!

library(shiny)
library(DT)

ui <- basicPage(
  h3("The mtcars data"),
  fluidRow(column(2,
                  offset = 1,
                  radioButtons("valSel", strong("Gear"),
                               inline = TRUE,
                               choices = c("3", "4", "5"),
                               selected = "3")),
           fluidRow(column(10,
                           offset = 1,
                           dataTableOutput("mytable")))
  )
)

server <- function(input, output) {
  
  output$mytable = DT::renderDataTable({
    mtcars[mtcars$gear == input$valSel, ]
  })
}

shinyApp(ui, server)

Created on 2021-05-27 by the reprex package (v2.0.0)

2 Answers

You can create a custom js function and switch to the desired page. Try this

library(shiny)
library(DT)
library(tidyverse)

ui <- basicPage(
  h3("The mtcars data"),
  fluidRow(column(2,
                  offset = 1,
                  radioButtons("valSel", strong("Gear"),
                               inline = TRUE,
                               choices = c("3", "4", "5"),
                               selected = "3")),
           fluidRow(column(10,
                           offset = 1, # verbatimTextOutput("t1"),
                           DTOutput("mytable")))
  ),
  tags$script(HTML(
    "Shiny.addCustomMessageHandler('pager',function(page) {
      $('#'+'mytable').find('table').DataTable().page(page).draw(false);
    })"
  ))
)

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

  mydf <- reactive({
    mtcars %>% mutate(rowid = row_number())
  })

  subdf <- reactive({
    req(mydf())
    mydf()[mydf()$gear == input$valSel, ]
  })
  output$t1 <- renderPrint({ceiling(min(subdf()$rowid)/10)})

  output$mytable = renderDT({
    n <- length(names(mydf())) ## to remove rowid
    mydf()[,-n]
  })

  observeEvent(input$valSel,{

    page <- ceiling(min(subdf()$rowid)/10) ## assumes 10 rows are displayed per page (default); if different, replace 10 by the number of rows displayed per page
    
    session$sendCustomMessage("pager",page-1)

  })

}

shinyApp(ui, server)

It isn't clear how you would identify the page where particular values are given they may contain different numbers of rows.

One alternative to setting the page would be to use the factor data type to reorder the categories depending on the radio button input, which would simply bring the category of interest to the top of the data frame being passed to renderDatatable:

library(shiny)
library(DT)

ui <- basicPage(
  h3("The mtcars data"),
  fluidRow(column(2,
                  offset = 1,
                  radioButtons("valSel", strong("Gear"),
                               inline = TRUE,
                               choices = c("3", "4", "5"),
                               selected = "3")),
           fluidRow(column(10,
                           offset = 1,
                           dataTableOutput("mytable")))
  )
)

server <- function(input, output) {
  
  df <- reactive({
    gear_vals <- unique(as.character(mtcars$gear))
    mtcars$gear <- factor(mtcars$gear, 
                          levels = c(input$valSel, 
                                     gear_vals[input$valSel != gear_vals]))
    mtcars[order(mtcars$gear),]
  })
  
  output$mytable = DT::renderDataTable({
    df()
  })
}

shinyApp(ui, server)
Related