在客户端使用afterChange事件更改rHandsontable的单元格背景

时间:2018-04-08 13:03:21

标签: r shiny handsontable shinyjs rhandsontable

我希望在用户在客户端编辑之后更改手环单元格的背景颜色。 handontable通过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)

2 个答案:

答案 0 :(得分:1)

搜索了一会儿之后,我使用了这些页面(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)

答案 1 :(得分:1)

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

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中的所有索引对表的所有col和行进行遍历。如果row和col索引都匹配,则此单元格的背景颜色将变为粉红色。