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

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

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

问题

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

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

library(shiny)
library(DT)

# 创建一个包含50个条目的示例数据框
df <- data.frame(
  name = paste0("Person ", 1:50),
  age = sample(20:60, 50, replace = TRUE),
  salary = sample(2000:5000, 50, replace = TRUE),
  stringsAsFactors = FALSE
)

# 创建一个Shiny应用程序
ui <- fluidPage(
  DTOutput("table")
)

server <- function(input, output, session) {
  # 创建一个reactiveValues对象来存储数据框
  rv <- reactiveValues()
  rv$df <- df
  
  # 渲染表格
  output$table <- renderDT({
    datatable(
      rv$df,
      rownames = FALSE,
      editable = TRUE,
      filter = "top",
      selection = "none",
      extensions = c(
        "ColReorder",
        "Buttons"
      ),
      options = list(
        dom = "lBRrftpi",
        autoWidth = FALSE,
        pageLength = 20,
        scrollX = FALSE,
        ColReorder = TRUE,
        buttons = list(list(extend = 'csv', filename= 'data'), 'print', 'copy')
      )
    )
  })
  
  # 在编辑后更新表格
  observeEvent(input$table_cell_edit, {
    info <- input$table_cell_edit
    i <- info$row
    j <- info$col
    v <- info$value
    
    new_i <- i
    new_j <- j + 1
    new_val <- v * 100
    new_info <- data.frame(
      row = new_i,
      col = new_j,
      value = new_val
    )
    
    rv$df <- editData(rv$df, info, rownames = FALSE)
    
    if(j == 1){
      rv$df <- editData(rv$df, new_info, rownames = FALSE)
    }
    
    replaceData(proxy = dataTableProxy("table"), data = rv$df, resetPaging = FALSE)
  })
  
}

# 运行应用程序
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

library(shiny)
library(DT)
# create a sample data frame with 50 entries
df &lt;- data.frame(
name = paste0(&quot;Person &quot;, 1:50),
age = sample(20:60, 50, replace = TRUE),
salary = sample(2000:5000, 50, replace = TRUE),
stringsAsFactors = FALSE
)
# create a shiny app
ui &lt;- fluidPage(
DTOutput(&quot;table&quot;)
)
server &lt;- function(input, output, session) {
# create a reactiveValues object to store the data frame
rv &lt;- reactiveValues()
rv$df &lt;- df
# render the table
output$table &lt;- renderDT({
datatable(
rv$df,
rownames = F,
editable = T,
filter = &quot;top&quot;,
selection = &quot;none&quot;,
extensions = c(
&quot;ColReorder&quot;,
&quot;Buttons&quot;
),
options = list(
dom = &quot;lBRrftpi&quot;,
autoWidth = F,
pageLength = 20,
scrollX = F,
ColReorder = T,
buttons = list(list(extend = &#39;csv&#39;, filename= &#39;data&#39;), &#39;print&#39;, &#39;copy&#39;)
)
)
})
# update the table when edited
observeEvent(input$table_cell_edit, {
info &lt;- input$table_cell_edit
i &lt;- info$row
j &lt;- info$col
v &lt;- info$value
new_i &lt;- i
new_j &lt;- j + 1
new_val &lt;- v * 100
new_info &lt;- data.frame(
row = new_i,
col = new_j,
value = new_val
)
rv$df &lt;&lt;- editData(rv$df, info, rownames = F)
if(j == 1){
rv$df &lt;&lt;- editData(rv$df, new_info, rownames = F)
}
replaceData(proxy = dataTableProxy(&quot;table&quot;), data = rv$df, resetPaging = FALSE)
})
}
# run the app
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了。

library(shiny)
library(DT)

# 创建一个包含50条条目的示例数据框
df <- data.frame(
  name = paste0("Person ", 1:50),
  age = sample(20:60, 50, replace = TRUE),
  salary = sample(2000:5000, 50, replace = TRUE),
  stringsAsFactors = FALSE
)

# 创建一个Shiny应用程序
ui <- fluidPage(
  DTOutput("table")
)

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

  # 渲染表格
  output$table <- renderDT({
    datatable(
      df,
      rownames = FALSE,
      editable = TRUE,
      filter = "top",
      selection = "none",
      extensions = c(
        "ColReorder",
        "Buttons"
      ),
      options = list(
        dom = "lBRrftpi",
        autoWidth = FALSE,
        pageLength = 20,
        scrollX = FALSE,
        ColReorder = TRUE,
        buttons = list(list(extend = 'csv', filename= 'data'), 'print', 'copy')
      )
    )
  })
  
  proxy <- dataTableProxy("table")
  
  # 当编辑时更新表格
  observeEvent(input$table_cell_edit, {
    info <- input$table_cell_edit
    i <- info$row
    j <- info$col
    v <- info$value
    
    new_i <- i
    new_j <- j + 1
    new_val <- v * 100
    new_info <- data.frame(
      row = new_i,
      col = new_j,
      value = new_val
    )
    
    df <- editData(df, info, proxy, rownames = FALSE)
    
    if(j == 1){
      df <- editData(df, new_info, proxy, rownames = FALSE)
    }
    
  })
  
}
英文:

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.

library(shiny)
library(DT)

# create a sample data frame with 50 entries
df &lt;- data.frame(
  name = paste0(&quot;Person &quot;, 1:50),
  age = sample(20:60, 50, replace = TRUE),
  salary = sample(2000:5000, 50, replace = TRUE),
  stringsAsFactors = FALSE
)

# create a shiny app
ui &lt;- fluidPage(
  DTOutput(&quot;table&quot;)
)

server &lt;- function(input, output, session) {

  # render the table
  output$table &lt;- renderDT({
    datatable(
      df,
      rownames = F,
      editable = T,
      filter = &quot;top&quot;,
      selection = &quot;none&quot;,
      extensions = c(
        &quot;ColReorder&quot;,
        &quot;Buttons&quot;
      ),
      options = list(
        dom = &quot;lBRrftpi&quot;,
        autoWidth = F,
        pageLength = 20,
        scrollX = F,
        ColReorder = T,
        buttons = list(list(extend = &#39;csv&#39;, filename= &#39;data&#39;), &#39;print&#39;, &#39;copy&#39;)
      )
    )
  })
  
  proxy &lt;- dataTableProxy(&quot;table&quot;)
  
  # update the table when edited
  observeEvent(input$table_cell_edit, {
    info &lt;- input$table_cell_edit
    i &lt;- info$row
    j &lt;- info$col
    v &lt;- info$value
    
    new_i &lt;- i
    new_j &lt;- j + 1
    new_val &lt;- v * 100
    new_info &lt;- data.frame(
      row = new_i,
      col = new_j,
      value = new_val
    )
    
    df &lt;&lt;- editData(df, info, proxy, rownames = F)
    
    if(j == 1){
      df &lt;&lt;- editData(df, new_info, proxy, rownames = F)
    }
    
  })
  
}

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:

确定