【问题标题】:Change cell background of rHandsontable with afterChange event on client side在客户端使用 afterChange 事件更改 rHandsontable 的单元格背景
【发布时间】:2018-09-17 23:27:46
【问题描述】:

我想在客户端用户编辑后更改可操作单元格的背景颜色。 Handsontable 是通过 Shiny 应用程序定义的;所以这真的是一个关于如何在 Shiny 应用程序的 rHandsontable 中定义事件挂钩的问题。我试图完成的一般用例是:用户编辑单元格数据;背景颜色更改以指示它已更改并且正在等待保存到数据库;更改将传递回 Shiny 的 observeEvent();更改被发送到外部数据库并保存; rHandsontable 在输出上用默认背景颜色重绘,删除颜色集作为更改。结果是闪烁表示数据已保存。如果出现数据库连接错误或其他问题,颜色将持续存在,表示数据未保存。我已经能够完成一个工作示例,粘贴在下面。

具体问题:钩子目前是使用hot_col(1,renderer=change_hook) 实现的,但这不是渲染单元格,只是一种允许添加钩子的方法。我假设hot_table() 是正确的函数,但它可以用来注册事件吗?更一般地说,有没有更内置的方法来实现这一点?

change_hook <- "
  function(instance, td, row, col, prop, value, cellProperties) {
Handsontable.hooks.add('afterChange', function(changes,source) { 
  if (source === 'edit' || source === 'undo' || source === 'autofill' || source === 'paste') {
    row = changes[0][0];
    col = changes[0][1];
    oldval = changes[0][2];
    newval = changes[0][3];

    if (oldval !== newval) {
      cell = this.getCell(row,col);
      cell.style.background = 'pink';
    }
  }
},instance);
Handsontable.renderers.TextRenderer.apply(this, arguments);
}"

ui <- div(width=300,rHandsontableOutput(outputId="hTable"))
server <- function(input, output, session) {

df<-data.frame(col1=c("Hands","on","Table"),col2=c(100,200,300),stringsAsFactors = F)
hTable <- reactiveVal(df)

observeEvent(input$hTable, {
withProgress(message = "Saving changes to database...", value=0.5, {

  Sys.sleep(1)

  incProgress(1, detail = "done")    
  input_hTable <- hot_to_r(input$hTable)
  hTable(input_hTable)
})
})

output$hTable <- renderRHandsontable({
rhandsontable(hTable(),stretchH="all",height=300) %>%
  hot_col(1,renderer=change_hook)
})
}
shinyApp(ui, server)

【问题讨论】:

    标签: r shiny handsontable shinyjs rhandsontable


    【解决方案1】:

    下面的代码在用户编辑rhandsontable单元格后改变了它的背景颜色。

    library(shiny)
    library(rhandsontable)
    
    ui <- fluidPage(
    titlePanel ('Give it a try and make changes!'),
    mainPanel(rHandsontableOutput('table'))
    )
    
    server <- function(input, output, session) {
    
    df <- data.frame(SYMBOLS = c('AAPL', 'ALRM', 'AMZN', 'BABA', 'CRM', 'CSCO', 
                                 'FB'),
                     NAMES = c('APPLE', 'ALARM.com', 'AMAZON', 'ALIBABA', 
                               'SALESFORCE', 'CISCO', 'FACEBOOK'),
                     NOTE = c('sale', '', 'buy', '', '', '', 'watch'))
    
    output$table <- renderRHandsontable(
        rhandsontable(df))
    
    rv <- reactiveValues(row = c(), col = c())
    
    observeEvent(input$table$changes$changes, {
        
        rv$row <- c(rv$row, input$table$changes$changes[[1]][[1]])
        rv$col <- c(rv$col, input$table$changes$changes[[1]][[2]])
        
        output$table <- renderRHandsontable({
            rhandsontable(hot_to_r(input$table), row_highlight = rv$row, 
                          col_highlight = rv$col) %>% 
                hot_cols(
                    renderer = "
                     function(instance, td, row, col, prop, value, cellProperties) {
                     Handsontable.renderers.TextRenderer.apply(this, arguments);
    
                     if (instance.params) {
                     hrows = instance.params.row_highlight;
                     hrows = hrows instanceof Array ? hrows : [hrows];
                     
                     hcols = instance.params.col_highlight;
                     hcols = hcols instanceof Array ? hcols : [hcols];
                     }
    
                     for (let i = 0; i < hrows.length; i++) {
                        if (instance.params && hrows[i] == row && hcols[i] == col) {
                        td.style.background = 'pink';
                        }}
                     }"
                    )
                })
            })
    }
    
    shinyApp(ui, server)
    

    每次改变一个单元格时,

    1. 此单元格的行索引 (input$table$changes$changes[[1]][[1]]) 及其列索引 (input$table$changes$changes[[1]][[2]]) 分别附加到反应变量 rv$rowrv$col
    2. 使用反应变量 (rv) 再次呈现 rHandsontable,其中包括到目前为止已更改的所有单元格的索引,最后,
    3. javascript 渲染器中的for 循环遍历rv 中的所有索引,每次一对针对表的所有列和行。如果行索引和列索引都匹配,则此单元格的背景颜色将更改为粉红色。

    【讨论】:

      【解决方案2】:

      搜索了一段时间后,我使用了这些页面中的信息(handsontablehtmlwidgets)来更改已编辑单元格的背景颜色。

      在 afterChange 函数中,将保留所有已更改单元格的列表。在 afterRender 函数中,这些单元格的背景颜色将变为黄色。在 afterLoadData 函数中,改变单元格的背景颜色将被重置为白色并被清空。

      library(shiny)
      library(rhandsontable)
      
      change_hook <- "function(el,x) {
      var hot = this.hot;  
      var cellChanges = [];
      
      var changefn = function(changes,source) { 
      if (source === 'edit' || source === 'undo' || source === 'autofill' || source === 'paste') {
      row = changes[0][0];
      col = changes[0][1];
      oldval = changes[0][2];
      newval = changes[0][3];
      
      if (oldval !== newval) {
        var cell = hot.getCell(row, col);
        cell.style.background = 'pink';
        cellChanges.push({'rowid':row, 'colid':col});
      }
      }
      }
      
      var renderfn = function(isForced) {
      
      for(i = 0; i < cellChanges.length; i++)
      {
      
      var rowIndex = cellChanges[i]['rowid'];
      var columnIndex = cellChanges[i]['colid'];
      
      var cell = hot.getCell(rowIndex, columnIndex);
      cell.style.background = 'yellow';
      
      }
      
      
      }
      
      var loadfn = function(initialLoad) {
      
      for(i = 0; i < cellChanges.length; i++)
          {
            var rowIndex = cellChanges[i]['rowid'];
            var columnIndex = cellChanges[i]['colid'];
      
            var cell = hot.getCell(rowIndex, columnIndex);
      
            cell.style.background = 'white';
      
          }
      cellChanges = []
      
      }
      
      
      hot.addHook('afterChange', changefn);
      hot.addHook('afterRender', renderfn);
      hot.addHook('afterLoadData', loadfn);
      
      
      }  "
      
      
      ui <- div(actionButton(inputId = "reset_button",label = "Reset")
                ,rHandsontableOutput(outputId="hTable"))
      
      
      server <- function(input, output, session) {
      
        df<-data.frame(col1=c("Hands","on","Table"),col2=c(100,200,300),stringsAsFactors = F)
        reset <- reactiveVal(0)
        hTable <- reactiveVal(df)
      
        output$hTable <- renderRHandsontable({
          r = reset()
          rht = rhandsontable(hTable(),reset=r,stretchH="all",height=300)%>%
            hot_col('col1',readOnly=T)
          reset(0)
          htmlwidgets::onRender(rht,change_hook)
        })
      
        observeEvent(input$reset_button,
                     {
                       reset(1)
                     })
      }
      
      shinyApp(ui, server)
      

      【讨论】:

        猜你喜欢
        • 2022-08-14
        • 1970-01-01
        • 1970-01-01
        • 2019-05-19
        • 2011-08-28
        • 2016-06-10
        • 2013-04-16
        • 2017-04-19
        • 1970-01-01
        相关资源
        最近更新 更多