Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R Shiny - multi-page editable DataTable jumps to row #1 after an edit

Tags:

r

dt

shiny

I am developing a Shiny app using R 3.3.1, Shiny v. 1.2.0 and v. DT 0.5. One of the elements is an editable data table that spans multiple pages. After I make an edit the row in focus jumps to row #1 which kind of ruins the user experience.

Here are the specific steps to reproduce this using the snippet below:

  1. Load the app
  2. Switch to page 2 of the data table
  3. Edit row 3, column 2: change Duh to Blue and press Tab
  4. Watch the current row jump to page 1 row 1. This would be easier to see if the were many more rows per page.

What I get in step 4 is not the desirable behavior. I want the data table to keep the focus on the same row I just edited.

I am open to using custom JS logic to make this work.

Seemingly related question - DataTable doesn't remember paginated page after edit but I do not know how to bridge from R to JS in this particular example.

 R.version.string
# "R version 3.3.1 (2016-06-21)"

library(shiny)  # v. 1.2.0
library(DT)  # v. 0.5

page_length <- 2 # 5 elements should span 3 pages

hardcoded_df <- read.table(text = "Fruit Color
                                   Apple Red
                                   Plum Purple
                                   Blueberry Duh
                                   Orange Carrot
                                   Crocodile Green",
                           header = TRUE,
                           stringsAsFactors = FALSE)

ui <- fluidPage(
   DT::dataTableOutput('x1')
)

server <- function(input, output) {
  x = reactiveValues(df = hardcoded_df)

   output$x1 = renderDT(DT::datatable(x$df, options = list(pageLength = page_length), selection = 'none', editable = TRUE))

   proxy = dataTableProxy('x1')

   observeEvent(input$x1_cell_edit, {
     info = input$x1_cell_edit
     str(info)

     # str(input$x1_state)
     i = info$row
     j = info$col
     v = info$value

     # Without this line the table does not change but with it it jumps to row 1 after an edit.
     x$df[i, j] <- isolate(DT::coerceValue(v, x$df[i, j]))

     # Now we need to scroll to row i somehow ... clearly this does not work. Help!
     selectPage(proxy, ceiling(i / page_length))
     # selectRow(proxy, i)
   })
}

# Run the application 
shinyApp(ui = ui, server = server)
like image 949
Leonid Avatar asked Mar 18 '19 06:03

Leonid


1 Answers

In this situation DT::replaceData with resetPaging = FALSE should work fine as shown here. However, defining x as a reactiveValues() cause some problems which I solved using isolate

 server <- function(input, output, session) {
    x = reactiveValues(df = hardcoded_df)
    output$x1 = renderDT(DT::datatable(isolate(x$df), 
                options = list(pageLength = page_length), selection = 'none', editable = TRUE))

    proxy = dataTableProxy('x1')

    data = reactiveValues()
    observeEvent(input$x1_cell_edit, {
      info = input$x1_cell_edit
      str(info)
      # str(input$x1_state)
      i = info$row
      j = info$col
      v = info$value

      # Without this line the table does not change but with it it jumps to row 1 after an edit.
      x$df[i, j] <- isolate(DT::coerceValue(v, x$df[i, j]))
      DT::replaceData(proxy, x$df, resetPaging = FALSE)  # important
      # Now we need to scroll to row i somehow ... clearly this does not work. Help!
      #selectPage(proxy, ceiling(i / page_length))
      # selectRow(proxy, i)
    })
  }
like image 115
A. Suliman Avatar answered Oct 23 '22 06:10

A. Suliman