I'd like to display to the user which cells have been updated before clicking a save button, and then clear the formatting. So, I'd like to change the color of edited cells. Can someone share an example of how to correctly do that? Or perhaps point me to one? I've looked around but can't seem to find a clear example.
Thanks!
Kerry
Hi Kerry,
I've been working on that last week and maybe I can help you.
In my case, I turn the lines red if they're being edited and only submit the changes to the database after clicking a "save" button:
I use meteor js, so the array "meteorData" comes from a mongodb collection.
What I do is to add an extra column to the dataset ("status") and then make the cell renderer depend on its value.
The changedRows array will hold all the modified records. Once the user clicks the save button, they are sent to the database.
Here's the code. Hope it helps.
var meteorData = [];
var container = document.getElementById('data-manager-content');
var redRenderer = function (instance, td, row, col, prop, value, cellProperties) {
Handsontable.renderers.TextRenderer.apply(this, arguments);
td.style.fontWeight = 'bold';
td.style.color = 'red';
};
var changedRows = [];
var hot = new Handsontable(container, {
readOnly: false,
//formulas:true,
stretchH: 'all',
data: meteorData,
height: 396,
minSpareRows: 1,
manualColumnResize: true,
colHeaders: [
'Status',
'Customer',
'Document No.',
'Date',
'Phone',
'Address',
'Postal Code',
'Vehicle',
'Closed',
'Updated'
],
rowHeaders: true,
autoWrapRow: true,
//colWidths: [200, 85, 70, 70, 70, 70, 70, 70],
contextMenu: {
items: {
"row_above": {
disabled: function () {
// if first row, disable this option
return hot.getSelected()[0] === 0;
}
},
"row_below": {},
"hsep1": "---------",
"remove_row": {},
"undo": {},
"redo": {},
"alignment": {}
}
},
beforeRemoveRow: function () {
console.log(this.getSelected());
//console.log(this.getSelectedRange());
console.log(meteorData[this.getSelected()[0]]);
return confirm("Are you sure you want to remove this row?");
},
columns: [
{
data: 'status',
readOnly: true
},
{data: 'customer'},
{data: 'docNo'},
{data: 'date', type: 'date', dateFormat: 'YYYY-MM-DD'},
{data: 'contactPhone'},
{data: 'address'},
{data: 'postCode'},
{
data: 'name',
type: 'dropdown',
source: _.uniq(DumbLists.find({}, {fields: {name: 1}}).map(function (it) {
return it.name
}))
},
{data: 'closed', type: 'checkbox', readOnly: true},
{data: 'confirmClose', type: 'checkbox', readOnly: true}
],
cells: function (row, col, prop) {
var cellProperties = {};
if (this.instance.getData()[row] && _.findWhere(['new', 'changed'],this.instance.getData()[row][0])) {
cellProperties.renderer = redRenderer; // uses function directly
}
return cellProperties;
},
afterChange: function (change, source) { // "change" is an array of arrays.
var rowIndex, columnIndex,statusValueAtCell,row, i;
//debugger;
console.log(source, change);
if (!change) {
return;
}
if (_.findWhere(['edit', 'autofill'], source)) { // Don't need to run this when data is loaded
for (i = 0; i < change.length; i++) { // For each change, get the change info and update the record
rowIndex = change[i][0]; // Which row it appears on Handsontable
row = meteorData[rowIndex]; // Now we have the whole row of data, including _id
var key = change[i][1]; // Handsontable docs calls this "prop"
var oldVal = change[i][2] || '';
var newVal = change[i][3];
var setModifier = {$set: {}}; // Need to build $set object
var randomId = Random.id();
var companyId = row && row.companyId;
var vehicleId = row && row.driverId;
if(key === 'status') {continue;}
//Set the status to "changed" for uncommited changes
statusValueAtCell = this.getDataAtCell(rowIndex, 0) || '';
if(statusValueAtCell){
// the record already exists on the table
if(oldVal !== newVal){
// The value was changed and not just edited
if(row && row._id){
// The record exists in meteor db
this.setDataAtCell(rowIndex, 0, 'changed');
}
// TODO: the changedRows array must contain the full mofifier for a given record. Then we send this to the tracker.
setModifier.$set[key] = newVal;
changedRows.push({
_id:row && row._id,
modifier:setModifier,
randomId:randomId,
companyId:companyId,
vehicleId:vehicleId
});
}
} else {
// the record doesn't exist on the table
this.setDataAtCell(rowIndex, 0, 'new');
setModifier.$set[key] = newVal;
changedRows.push({
_id:row && row._id,
modifier:setModifier,
randomId:randomId,
companyId:companyId,
vehicleId:vehicleId
});
}
}
} else {
if (source === 'loadData') {
// do nothing!
console.log('loadData',source, change);
} else {
// It's a paste event
for (i = 0; i < change.length; i++) { // For each change, get the change info and update the record
rowIndex = change[i][0];
row = meteorData[rowIndex]; // Now we have the whole row of data, including _id
console.log(row);
if(row && row._id){
this.setDataAtCell(rowIndex, 0, 'changed');
} else {
this.setDataAtCell(rowIndex, 0, 'new');
}
}
}
}
}
});