如何在 Shiny 应用中编辑后保留数据表的筛选(或不同页面)视图?

huangapple go评论95阅读模式
英文:

How to retain the filtered (or different page) view of a datatable after editing in a Shiny app?

问题

我正在编写一个Shiny应用程序,其中我正在呈现一个可编辑的数据表。在某些情况下,我希望用户可以筛选表格或转到不同的页面,然后对表格进行编辑。在进行编辑之后,我希望表格的当前视图保持不变,同时显示表格中的编辑内容。对列的编辑还会更改另一列中的值,因此这两个编辑需要同时显示在保持视图的同时。

这是我迄今为止编写的代码:

  1. library(shiny)
  2. library(DT)
  3. # 创建一个包含50个条目的示例数据框
  4. df <- data.frame(
  5. name = paste0("Person ", 1:50),
  6. age = sample(20:60, 50, replace = TRUE),
  7. salary = sample(2000:5000, 50, replace = TRUE),
  8. stringsAsFactors = FALSE
  9. )
  10. # 创建一个Shiny应用程序
  11. ui <- fluidPage(
  12. DTOutput("table")
  13. )
  14. server <- function(input, output, session) {
  15. # 创建一个reactiveValues对象来存储数据框
  16. rv <- reactiveValues()
  17. rv$df <- df
  18. # 渲染表格
  19. output$table <- renderDT({
  20. datatable(
  21. rv$df,
  22. rownames = FALSE,
  23. editable = TRUE,
  24. filter = "top",
  25. selection = "none",
  26. extensions = c(
  27. "ColReorder",
  28. "Buttons"
  29. ),
  30. options = list(
  31. dom = "lBRrftpi",
  32. autoWidth = FALSE,
  33. pageLength = 20,
  34. scrollX = FALSE,
  35. ColReorder = TRUE,
  36. buttons = list(list(extend = 'csv', filename= 'data'), 'print', 'copy')
  37. )
  38. )
  39. })
  40. # 在编辑后更新表格
  41. observeEvent(input$table_cell_edit, {
  42. info <- input$table_cell_edit
  43. i <- info$row
  44. j <- info$col
  45. v <- info$value
  46. new_i <- i
  47. new_j <- j + 1
  48. new_val <- v * 100
  49. new_info <- data.frame(
  50. row = new_i,
  51. col = new_j,
  52. value = new_val
  53. )
  54. rv$df <- editData(rv$df, info, rownames = FALSE)
  55. if(j == 1){
  56. rv$df <- editData(rv$df, new_info, rownames = FALSE)
  57. }
  58. replaceData(proxy = dataTableProxy("table"), data = rv$df, resetPaging = FALSE)
  59. })
  60. }
  61. # 运行应用程序
  62. shinyApp(ui, server)

尽管表格中的编辑和另一列的相关更改确实有效,但表格视图在编辑单元格后重置。有人可以帮助我编写代码,以在编辑后保持视图吗?

英文:

I am writing a Shiny app where I am rendering an editable datatable. In some instances I would like the user to filter the table or go to a different page and then make edits to the table. After this editing, I would like the current view of the table to remain while showing the edits in the table. The editing of a column also changes the values in another column, so both these edits need to be displayed while retaining the view.

This is the code I have come up with so far

  1. library(shiny)
  2. library(DT)
  3. # create a sample data frame with 50 entries
  4. df &lt;- data.frame(
  5. name = paste0(&quot;Person &quot;, 1:50),
  6. age = sample(20:60, 50, replace = TRUE),
  7. salary = sample(2000:5000, 50, replace = TRUE),
  8. stringsAsFactors = FALSE
  9. )
  10. # create a shiny app
  11. ui &lt;- fluidPage(
  12. DTOutput(&quot;table&quot;)
  13. )
  14. server &lt;- function(input, output, session) {
  15. # create a reactiveValues object to store the data frame
  16. rv &lt;- reactiveValues()
  17. rv$df &lt;- df
  18. # render the table
  19. output$table &lt;- renderDT({
  20. datatable(
  21. rv$df,
  22. rownames = F,
  23. editable = T,
  24. filter = &quot;top&quot;,
  25. selection = &quot;none&quot;,
  26. extensions = c(
  27. &quot;ColReorder&quot;,
  28. &quot;Buttons&quot;
  29. ),
  30. options = list(
  31. dom = &quot;lBRrftpi&quot;,
  32. autoWidth = F,
  33. pageLength = 20,
  34. scrollX = F,
  35. ColReorder = T,
  36. buttons = list(list(extend = &#39;csv&#39;, filename= &#39;data&#39;), &#39;print&#39;, &#39;copy&#39;)
  37. )
  38. )
  39. })
  40. # update the table when edited
  41. observeEvent(input$table_cell_edit, {
  42. info &lt;- input$table_cell_edit
  43. i &lt;- info$row
  44. j &lt;- info$col
  45. v &lt;- info$value
  46. new_i &lt;- i
  47. new_j &lt;- j + 1
  48. new_val &lt;- v * 100
  49. new_info &lt;- data.frame(
  50. row = new_i,
  51. col = new_j,
  52. value = new_val
  53. )
  54. rv$df &lt;&lt;- editData(rv$df, info, rownames = F)
  55. if(j == 1){
  56. rv$df &lt;&lt;- editData(rv$df, new_info, rownames = F)
  57. }
  58. replaceData(proxy = dataTableProxy(&quot;table&quot;), data = rv$df, resetPaging = FALSE)
  59. })
  60. }
  61. # run the app
  62. shinyApp(ui, server)

While the edits in the table and the dependant changes in the other column do work, the table view resets as soon as I edit a cell. Can someone please help me with code that retains the view after editing?

答案1

得分: 1

你观察到的情况是因为你使用的数据对象是响应式的,当你更新它时,表格会在更新发生时重新渲染。使用代理的一个很酷的地方是你不需要一个响应式数据对象。此外,你可以将代理对象传递给editData,然后就不需要replaceData了。

  1. library(shiny)
  2. library(DT)
  3. # 创建一个包含50条条目的示例数据框
  4. df <- data.frame(
  5. name = paste0("Person ", 1:50),
  6. age = sample(20:60, 50, replace = TRUE),
  7. salary = sample(2000:5000, 50, replace = TRUE),
  8. stringsAsFactors = FALSE
  9. )
  10. # 创建一个Shiny应用程序
  11. ui <- fluidPage(
  12. DTOutput("table")
  13. )
  14. server <- function(input, output, session) {
  15. # 渲染表格
  16. output$table <- renderDT({
  17. datatable(
  18. df,
  19. rownames = FALSE,
  20. editable = TRUE,
  21. filter = "top",
  22. selection = "none",
  23. extensions = c(
  24. "ColReorder",
  25. "Buttons"
  26. ),
  27. options = list(
  28. dom = "lBRrftpi",
  29. autoWidth = FALSE,
  30. pageLength = 20,
  31. scrollX = FALSE,
  32. ColReorder = TRUE,
  33. buttons = list(list(extend = 'csv', filename= 'data'), 'print', 'copy')
  34. )
  35. )
  36. })
  37. proxy <- dataTableProxy("table")
  38. # 当编辑时更新表格
  39. observeEvent(input$table_cell_edit, {
  40. info <- input$table_cell_edit
  41. i <- info$row
  42. j <- info$col
  43. v <- info$value
  44. new_i <- i
  45. new_j <- j + 1
  46. new_val <- v * 100
  47. new_info <- data.frame(
  48. row = new_i,
  49. col = new_j,
  50. value = new_val
  51. )
  52. df <- editData(df, info, proxy, rownames = FALSE)
  53. if(j == 1){
  54. df <- editData(df, new_info, proxy, rownames = FALSE)
  55. }
  56. })
  57. }
英文:

What you observe is occuring because the data object you use is reactive and you update it, and then the table is re-rendered when the update occurs. The cool thing with a proxy is that you don't need a reactive data object. Also, you can pass the proxy object to editData and then there's no need of replaceData.

  1. library(shiny)
  2. library(DT)
  3. # create a sample data frame with 50 entries
  4. df &lt;- data.frame(
  5. name = paste0(&quot;Person &quot;, 1:50),
  6. age = sample(20:60, 50, replace = TRUE),
  7. salary = sample(2000:5000, 50, replace = TRUE),
  8. stringsAsFactors = FALSE
  9. )
  10. # create a shiny app
  11. ui &lt;- fluidPage(
  12. DTOutput(&quot;table&quot;)
  13. )
  14. server &lt;- function(input, output, session) {
  15. # render the table
  16. output$table &lt;- renderDT({
  17. datatable(
  18. df,
  19. rownames = F,
  20. editable = T,
  21. filter = &quot;top&quot;,
  22. selection = &quot;none&quot;,
  23. extensions = c(
  24. &quot;ColReorder&quot;,
  25. &quot;Buttons&quot;
  26. ),
  27. options = list(
  28. dom = &quot;lBRrftpi&quot;,
  29. autoWidth = F,
  30. pageLength = 20,
  31. scrollX = F,
  32. ColReorder = T,
  33. buttons = list(list(extend = &#39;csv&#39;, filename= &#39;data&#39;), &#39;print&#39;, &#39;copy&#39;)
  34. )
  35. )
  36. })
  37. proxy &lt;- dataTableProxy(&quot;table&quot;)
  38. # update the table when edited
  39. observeEvent(input$table_cell_edit, {
  40. info &lt;- input$table_cell_edit
  41. i &lt;- info$row
  42. j &lt;- info$col
  43. v &lt;- info$value
  44. new_i &lt;- i
  45. new_j &lt;- j + 1
  46. new_val &lt;- v * 100
  47. new_info &lt;- data.frame(
  48. row = new_i,
  49. col = new_j,
  50. value = new_val
  51. )
  52. df &lt;&lt;- editData(df, info, proxy, rownames = F)
  53. if(j == 1){
  54. df &lt;&lt;- editData(df, new_info, proxy, rownames = F)
  55. }
  56. })
  57. }

huangapple
  • 本文由 发表于 2023年3月3日 18:43:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/75626045.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定