问题
I am creating a Shiny app that displays data.frame information at the top of the screen and specific variable stats at the bottom. The user can navigate the data.frame columns by interacting with a DT::datatable
object.
When a user clicks on a variable, detailed information is presented that can be edited. I would like this information to be updated and reflected in the datatable. My problem is that when I update the table, it is rendered and shown starting at the very beginning. How can I preserve the page and row selection of the datatable after making edits?
Here is a minimal working example that shows the mtcars dataset in a DT::datatable
. I have some controls that update fields. Notice that datatable is re-rendered back to the first page.
library(shiny)
runApp(shinyApp(
ui = fluidPage(
title = "minimal-working-example",
fluidRow(
column(3, inputPanel(
selectInput("field", "Field", choices = names(mtcars)),
numericInput("value", "Value", 0),
actionButton("submit", "Submit")
)),
column(9,
DT::dataTableOutput("table")
)
)
),
server = function(input, output) {
v <- reactiveValues(mtcars=mtcars)
observeEvent(input$submit, {
v$mtcars[input$field] <- input$value
})
output$table <- DT::renderDataTable({
DT::datatable(
v$mtcars,
selection = "single",
options = list(pageLength = 5))
})
}
))
Session Info:
Session info --------------------------
setting value
version R version 3.3.0 (2016-05-03)
system x86_64, mingw32
ui RStudio (0.99.902)
language (EN)
collate English_United States.1252
tz America/Chicago
date 2016-07-11
Packages -------------------------------
package * version date source
DT 0.1.45 2016-02-09 Github (rstudio/DT@a63e9ac)
shiny * 0.13.0.9000 2016-02-08 Github (rstudio/shiny@e871934)
回答1:
This can be done from inside R without getting into the structure of the datatable
through JS or something like that.
We utilize the various table state information we get from the DT
package to render the new updated datatable
like the one before. Everything we use is discribed in this DT documentation.
Item one: Selection. You can pre-select rows by adding selected = ...
inside the selection
argument of the datatable. This can be combined with the variable input$table_rows_selected
to save the previously selected row and pre-select that exact row on re-rendering.
Item two: Page. The datatable
package has an option displayStart
that specifies which row should be shown first when rendering the table. Documentation here. So, if you have 5 rows per page, displayStart = 9
would start the display on page 3. (JavaScript arrays start at 0, so always subtract 1.) This can be combined with input$table_rows_current
which is a vector of currently visible row numbers. If we store the first entry (minus 1), we know where to start the display.
Full code example below:
library(shiny)
runApp(shinyApp(
ui = fluidPage(
title = "minimal-working-example",
fluidRow(
column(3, inputPanel(
selectInput("field", "Field", choices = names(mtcars)),
numericInput("value", "Value", 0),
actionButton("submit", "Submit")
)),
column(9,
DT::dataTableOutput("table")
)
)
),
server = function(input, output) {
v <- reactiveValues(mtcars=mtcars)
previousSelection <- NULL
previousPage <- NULL
observeEvent(input$submit, {
previousSelection <<- input$table_rows_selected
previousPage <<- input$table_rows_current[1] - 1
v$mtcars[input$field] <- input$value
})
output$table <- DT::renderDataTable({
DT::datatable(
v$mtcars,
selection = list(mode = "single", target = "row", selected = previousSelection),
options = list(pageLength = 5, displayStart = previousPage))
})
}
))
来源:https://stackoverflow.com/questions/38316013/update-rows-of-a-shiny-datatable-while-maintaining-position