Search code examples
knockout.jshandsontable

How to put a computed observable as a cell data in Handsontable


I have already integration of Handsontable with KnockoutJS here http://jsfiddle.net/NHpEH.

     ko.bindingHandlers.handsontable = {
        init: function (element, valueAccessor, allBindingsAccessor) {
            var value = valueAccessor(); // TODO: what happens if value is null?         
            var allBindings = allBindingsAccessor();
            var colHeaders = allBindings.colHeaders() || true;
            var data = allBindings.handsontable();

            // TODO: make options customizable
            $(element).handsontable({
                data: data,
                minRows: value().length || 5,
                minCols: value()[0].length || 5,
                minSpareCols: 0,
                minSpareRows: 1,
                colHeaders: colHeaders,
                contextMenu: true,
                onChange: function (data, source) {
                    var headers = $(element).handsontable("getColHeader")
                    var tableData = $(element).handsontable("getData");

                    value(tableData);

                    allBindings.colHeaders(headers);
                }
            });

            $(element).handsontable("loadData", value());
        },
        update: function (element, valueAccessor, allBindingsAccessor) {
            var value = valueAccessor();
            var valueUnwrapped = ko.utils.unwrapObservable(value);
            var allBindings = allBindingsAccessor();
            var colHeaders = allBindings.colHeaders();

            $(element).handsontable("updateSettings", {
                minRows: value().length,
                minCols: value()[0].length
            });
        }
    };

but I want to put a computed observable as a cell data in a cell. For example I want to show sum of two other cells in a cell.

Any idea would be appreciated.


Solution

  • OK, This is my solution. The code snippet is not optimized and is just a simple idea.

    In this way, you can specify a computed observable for each specific cell. The third column is sum of the first three columns and the fourth column is multiply of them. jsfiddle

     function SumRowRenderer(instance, td, row, col, prop, value, cellProperties) {
         td.innerHTML = '<b>' + viewModel.SumForFirstRow() + '</b>';
         $(td).css({
             background: 'yellow'
         });
     }
    
     function MultiplyRowRenderer(instance, td, row, col, prop, value, cellProperties) {
         td.innerHTML = '<b>' + viewModel.MultiplyForFirstRow() + '</b>';
         $(td).css({
             background: 'pink'
         });
     }
     ko.bindingHandlers.handsontable = {
         init: function (element, valueAccessor, allBindingsAccessor) {
             var value = valueAccessor(); // TODO: what happens if value is null?         
             var allBindings = allBindingsAccessor();
             var colHeaders = allBindings.colHeaders() || true;
    
             var data = value();
    
             $(element).handsontable({
                 data: data,
                 minRows: value().length ? (value().length) : 5,
                 minCols: value()[0].length || 5,
                 minSpareCols: 0,
                 minSpareRows: 0,
                 colHeaders: colHeaders,
                 contextMenu: false,
                 onChange: function (data, source) {
                     var headers = $(element).handsontable("getColHeader")
                     var tableData = $(element).handsontable("getData");
    
                     value(tableData);
    
                     allBindings.colHeaders(headers);
                 },
                 cells: function (row, col, prop) {
                     if (row == 0) {
                         if (col === 3) {
                            return { type: { renderer: SumRowRenderer,readOnly: true}};
                         } else if (col === 4) {
                            return {type: {renderer: MultiplyRowRenderer,readOnly: true}};
                         }
                     }
                 }
             });
    
         },
         update: function (element, valueAccessor, allBindingsAccessor) {
             var value = valueAccessor();
             var valueUnwrapped = ko.utils.unwrapObservable(value);
             var allBindings = allBindingsAccessor();
             var colHeaders = allBindings.colHeaders();
    
             $(element).handsontable("updateSettings", {
                 minRows: value().length,
                 minCols: value()[0].length
             });
         }
     };
    
     var viewModel = {
         data: ko.observableArray([
    
             [10, 10, 12, 0, 0]
    
         ]),
         colHeaders: ko.observableArray(["One", "Two", "Three", "Sum", "Multiply"])
     };
    
     viewModel.SumForFirstRow = ko.computed(function () {
    
         return parseInt(this.data()[0][0]) +
         parseInt(this.data()[0][1]) + 
         parseInt(this.data()[0][2]);
    
     }, viewModel);
     viewModel.MultiplyForFirstRow = ko.computed(function () {
    
         return parseInt(this.data()[0][0]) *
         parseInt(this.data()[0][1]) * 
         parseInt(this.data()[0][2]);
    
     }, viewModel);
    
     ko.applyBindings(viewModel);