rshinyreactable

How to jump to a reactable page upon modifying the underlying data?


I'm trying to use the reactable package to hop to a specific row index after a user modifies the data underlying the reactable.

library(shiny)
library(reactable)
library(dplyr)

ui <- fluidPage(
    selectInput("index", "Index", choices = seq_len(nrow(iris))),
    selectInput("species", "Species", choices = unique(iris$Species)),
    actionButton("go", "Modify"),
    reactableOutput("table")
)

server <- function(input, output, session) {
    # Reactive data
    data <- reactiveValues(
        data = iris |> mutate(Index = row_number())
    )

    # Render reactable
    output$table <- renderReactable({
        reactable(data$data)
    })

    # Update data on button click
    observeEvent(
        input$go,
        {
            # modify the one record
            x <- data$data |>
                filter(Index == input$index) |>
                mutate(Species = input$species)

            # rm from all data
            data$data <- data$data |>
                filter(Index != input$index) |>
                bind_rows(x) |>
                arrange(Index)

            # get index of change
            index <- x |> pull(Index)

            # hop to that approximate page
            updateReactable("table", page = ceiling(index / 10))
        }
    )
}

shinyApp(ui, server)

The observeEvent() successfully updates the data but does not hop to the page of the modified index. I.e., if a user is on page 1 but modifies the record with Index == 44 from setosa to versicolor, I'd like to use reactable::updateReactable() to jump to that page. When running this code, it looks like it tries to jump to the page before the reactable output renders the new data, which is what I'm assuming the issue is.


Solution

  • isolate() will work in this case, but can cause issues if something in the table requires rendering on each update (i.e., an icon). See this follow-up SO question.

    library(shiny)
    library(reactable)
    library(dplyr)
    
    ui <- fluidPage(
        actionButton("go", "Add Observation"),
        reactableOutput("table")
    )
    
    server <- function(input, output, session) {
        # Reactive data
        data <- reactiveValues(
            data = iris |> mutate(Index = row_number()),
            tbl_page = 1
        )
    
        # Render reactable, but isolate
        output$table <- renderReactable({
            data$data |>
                reactable() |>
                htmlwidgets::onRender(
                    "function(el, x) {
                     Shiny.setInputValue('tbl_rendered', Date.now())
                     }"
                )
        })
    
        # Update data on button click
        observeEvent(
            input$go,
            {
                # create a record to add
                x <- data$data |>
                    dplyr::slice_sample(n = 1) |>
                    dplyr::mutate(Index = nrow(data$data) + 1)
    
    
                # add a record and re id
                data$data <- bind_rows(
                    data$data,
                    x
                ) |>
                    dplyr::arrange(Index)
    
                # get index of change, save the needed page
                index <- tail(data$data, 1) |> dplyr::pull(Index)
    
                # update reactiveVals
                data$tbl_page <- ceiling(index / 10)
            }
        )
    
        # jump to page after table has rendered
        shiny::observeEvent(
            input$tbl_rendered,
            reactable::updateReactable("table", page = data$tbl_page)
        )
    }
    
    shinyApp(ui, server)