Search code examples
handsontable

Handsontable: Updating a cell renderer at runtime


I'm using handsontable, and I want to change the background color of a cell if its value is edited and changed. I can do this easily if my data source is an array of arrays (see fiddle: http://jsfiddle.net/chiman24/3o2c3c7m/).

document.addEventListener("DOMContentLoaded", function() {

    // Row Styles
    var blank = function(instance, td, row, col, prop, value,
        cellProperties) {
        Handsontable.renderers.TextRenderer.apply(this, arguments);
        td.style.backgroundColor = '#ABAAAA'
    };

    var align = function(instance, td, row, col, prop, value,
        cellProperties) {
        Handsontable.renderers.TextRenderer.apply(this, arguments);
        td.style.verticalAlign = 'middle';
        td.style.fontWeight = 'bold';
    };

    var highlight1 = function(instance, td, row, col, prop, value,
        cellProperties) {
        Handsontable.renderers.TextRenderer.apply(this, arguments);
        td.style.backgroundColor = '#BDD7EE';
        td.style.textAlign = 'right';
    };

    var changedBackgroundColor = '#cbd9e4';
    var defaultBackgroundColor = 'white';
    var hasChanged = function(instance, td, row, col, prop, value,
        cellProperties) {
        Handsontable.renderers.TextRenderer.apply(this, arguments);
        td.style.backgroundColor = changedBackgroundColor;
    };
    var noChange = function(instance, td, row, col, prop, value,
        cellProperties) {
        Handsontable.renderers.TextRenderer.apply(this, arguments);
        td.style.backgroundColor = defaultBackgroundColor;
    };

    var data = [
            ["1", "Hear us from heaven", "New Life Worship",
                "Anderson, Jared", "something"
            ],
            ["2", "Spirit Break Out", "Kim Walker", "Walker, Kim",
                "Still Believe"
            ]
        ],
        dataCopy = [
            ["1", "Hear us from heaven", "New Life Worship",
                "Anderson, Jared", "something"
            ],
            ["2", "Spirit Break Out", "Kim Walker", "Walker, Kim",
                "Still Believe"
            ]
        ],
        container = document.getElementById('example1'),
        hot1;


    //Table Row and Col Options
    hot1 = new Handsontable(container, {
        data: data,
        fixedColumnsLeft: 1,
        columnSorting: true,
        colHeaders: ["id", "title", "artist", "author", "album"],
        columns: [{
            type: "text"
        }, {
            type: "text"
        }, {
            type: "text"
        }, {
            type: "text"
        }, {
            type: "text"
        }]
    });

    hot1.addHook('afterChange', afterChange);

    function afterChange(changes, source) {
        if (source == 'edit' || source == 'autofill') {
            $.each(changes, function(index, element) {
                var change = element;
                var rowIndex = change[0];
                var columnIndex = change[1];
                var oldValue = change[2];
                var newValue = change[3];
                var cellChange = {
                    'rowIndex': rowIndex,
                    'columnIndex': columnIndex
                };
                if (oldValue != newValue) {
                    var cellProperties = hot1.getCellMeta(
                        rowIndex, columnIndex);
                    if (newValue != dataCopy[rowIndex][
                            columnIndex
                        ]) {
                        cellProperties.renderer = hasChanged;
                    } else { //data changed back to original value.
                        cellProperties.renderer = noChange;
                    }
                    hot1.render();
                }
            });
        }
    }
});


// noSideScroll class added to fix some containers while side scrolling the table
$(window).scroll(function() {
    $('.noSideScroll').css({
        'left': $(this).scrollLeft()
    });
});

However, when using an array of objects, I can't get it to work. (see fiddle: http://jsfiddle.net/chiman24/24mpavga/).

var data = [{
        "id": 1,
        "title": "First Loved Me",
        "artist": "Israel and New Breed",
        "author": "Houghton, Israel",
        "album": "Covered:  Alive In Asia"
    }, {
        "id": 2,
        "title": "One Thing Remains",
        "artist": "Israel and New Breed",
        "author": "Houghton, Israel",
        "album": "Covered:  Alive In Asia"
    }],
    dataCopy = [{
        "id": 1,
        "title": "First Loved Me",
        "artist": "Israel and New Breed",
        "author": "Houghton, Israel",
        "album": "Covered:  Alive In Asia"
    }, {
        "id": 2,
        "title": "One Thing Remains",
        "artist": "Israel and New Breed",
        "author": "Houghton, Israel",
        "album": "Covered:  Alive In Asia"
    }],
    container = document.getElementById('example1'),
    hot1;


//Table Row and Col Options
hot1 = new Handsontable(container, {
    data: data,
    fixedColumnsLeft: 1,
    columnSorting: true,
    colHeaders: ["id", "title", "artist", "author", "album"],
    columns: [{
        data: "id"
    }, {
        data: "title"
    }, {
        data: "artist"
    }, {
        data: "author"
    }, {
        data: "album"
    }]
});

hot1.addHook('afterChange', afterChange);

function afterChange(changes, source) {
    if (source == 'edit' || source == 'autofill') {
        $.each(changes, function(index, element) {
            var change = element;
            var rowIndex = change[0];
            var columnIndex = change[1];
            var oldValue = change[2];
            var newValue = change[3];
            var cellChange = {
                'rowIndex': rowIndex,
                'columnIndex': columnIndex
            };
            if (oldValue != newValue) {
                var cellProperties = hot1.getCellMeta(
                    rowIndex, columnIndex);
                if (newValue != dataCopy[rowIndex][
                        columnIndex
                    ]) {
                    cellProperties.renderer = hasChanged;
                } else { //data changed back to original value.
                    cellProperties.renderer = noChange;
                }
                hot1.render();
            }
        });
    }
}

Is there a way to accomplish this? I want to get it working using an array of objects because my data coming from the server will be in JSON format. I've scoured the handsontable documentation for a couple of days to no avail. Any help will be much appreciated. Thanks.


Solution

  • I got some help from the handsontable github forum.

    Apparently, if the data source is an array of objects, then when calling "getCellMeta", instead of passing in a numerical column index, you have to pass in the column index as a property like this:

    hot.getCellMeta(2, hot.propToCol(columnIndex));
    

    Here's the updated demo