首页 > 解决方案 > 在 rhandsontable 中插入重复行

问题描述

我在 Shiny 仪表板中使用 rhandsontable 包,并希望在上下文菜单中添加自定义“复制行”选项,用户可以在其中复制一行并将重复的行插入到表中(即,复制一整行并插入原始行下方的副本)。这有助于防止错误并通过在新行中编辑更少的单元格来节省用户时间。不幸的是,我没有使用 JavaScript 的经验,也不知道如何创建这个选项。我正在关注有关自定义菜单选项的相关问题,但尚未收到任何回复。

如何添加自定义上下文菜单选项以复制表格行并将其插入到下面的新行中?谢谢你的帮助!

代表


library(shiny)
library(shinyjs)
library(htmlwidgets)
library(tidyverse)
library(rhandsontable)
library(datasets)

ui <- fluidPage(
  titlePanel("Edit Iris"),
      mainPanel(rHandsontableOutput("iris_table"))
)

server <- function(input, output, session) {
  
  data(iris)
  summary(iris)
  
  copy_row_js <- "function (key, selection, clickEvent) {
                    this.alter('insert_row');
                    this.render();
                  }"
  
  output$iris_table <- renderRHandsontable({
    
    table <- rhandsontable(iris,
                           rowHeaders = FALSE) %>%
      hot_context_menu(allowRowEdit = TRUE, 
                       allowColEdit = FALSE,
                       customOpts = list(
                         copy_row = list(
                           name = "Copy row",
                           callback = htmlwidgets::JS(copy_row_js))
                       )
      )
    
    table
    
  })
  
}

shinyApp(ui = ui, server = server)

更新

我不知道如何将此选项添加到上下文菜单中,因此我创建了一个“复制行”按钮以使用 reactiveValues 实现相同的功能(作弊,但我需要一种解决方法)。这个关于访问 rhandsontable 值的答案非常有帮助。一个新的挑战:在改变过滤器输入后,reactive() 过滤器突然没有重新运行。我创建了一个 reprex,但奇怪的是,这个 reprex 似乎有效(?),因为 iris 数据集过滤器在更改所选物种输入后重新运行。更复杂的应用程序中的过滤器不会重新运行。关于可能发生的事情有什么建议吗?

library(shiny)
library(shinyjs)
library(htmlwidgets)
library(tidyverse)
library(rhandsontable)
library(datasets)

data("iris")
summary(iris)

ui <- fluidPage(
  titlePanel("Edit Iris"),
  sidebarLayout(
    sidebarPanel(
      selectizeInput("iris_species", "Iris Species", 
                  choices = iris$Species,
                  multiple = FALSE,
                  selected = (iris$Species == "setosa")),
      br(),
      actionButton("copy_row", "Copy Row"),
      br(),
      actionButton("reset", "Reset"),
      br(),
    ),
  mainPanel(rHandsontableOutput("iris_table"))
  )
)

server <- function(input, output, session) {
  
  data("iris")
  summary(iris)
  
  df <- reactive({
    
    input$iris_species
    
    data("iris")
    summary(iris)
    
    df <- iris %>%
      filter(Species == input$iris_species) %>%
      arrange(Species, Sepal.Length)
    df
  })
  
  iris_values <- reactiveValues(data = as.data.frame(NULL))
  
  # Beginning state: filter data by input$iris_species
  observeEvent(input$iris_species, {
      iris_values$data <- df()
  })
  
  # Reset to initially displayed df(), deleting any user changes
  observeEvent(input$reset, {
    iris_values$data <- df()
  })
  
  # Copy row for additional Sepal.Length entries by user
  observeEvent(input$copy_row, {
    
    row_select <- input$iris_table_select$select$r
    
    copy_row <- as.data.frame(hot_to_r(req(input$iris_table))) %>%
      slice(row_select)
    
    iris_values$data <- as.data.frame(hot_to_r(req(input$iris_table))) %>%
      bind_rows(copy_row) %>%
      arrange(Species, Sepal.Length)
  })
  
  # Output handsontable
  output$iris_table <- renderRHandsontable({
    
    table <- rhandsontable({iris_values$data},
                           rowHeaders = FALSE,
                           height = 500,
                           width = 1000,
                           selectCallback = TRUE) %>%
      hot_context_menu(allowRowEdit = TRUE,
                       allowColEdit = FALSE
      )
    
    table

  })
}

shinyApp(ui = ui, server = server)

解决

正在寻找“不重新运行”问题的答案并发现了这个答案,描述了对已验证反应器的依赖如何可能不会传递验证错误。成功!我发现“复制”按钮非常有用——在感兴趣的情况下将其发布。

标签: rshinyrhandsontable

解决方案


推荐阅读