Search code examples
jqueryknockout.jsknockout-mapping-plugin

Knockout Computed sum of Nested list


I'm trying to calculate the sum of the values of a nested sub list, the VM in which I want to query is being mapped with the KO mapper and then extended with my computed feilds. It can't seem to find the nested array that I'm looking for:

var HouseholdViewModel = function(data) {
    this.$type = 'HouseholdViewModel';
    ko.mapping.fromJS(data, mapping, this);

    this.T12 = ko.computed(function () {
        var total = 0;
        ko.utils.arrayForEach(this.Accounts(), function (account) {
            total += account.T12Revenue();
        });
        return total;
    }, this);

};

var AccountViewModel = function(data) {
    this.$type = 'AccountViewModel';
    ko.mapping.fromJS(data, mapping, this);
};

var mapping = {
    'Households': {
        create: function(options) {
            return new HouseholdViewModel(options.data);
        }
    },
    'Accounts': {
        create: function(options) {
            return new AccountViewModel(options.data);
        }
    }
};

I get the error message 'Uncaught TypeError: Object [object Object] has no method 'Accounts' '. I am hypothesising that this is due to KO.Mapper not having bound the Accounts yet but the mapping call is above the calculated observable. Any help would be greatly appreciated.


Solution

  • An easy fix for this is to make sure you have Accounts before you try to use it in a computed. When Accounts exists this will notify your computed to recompute -

    var HouseholdViewModel = function(data) {
        this.$type = 'HouseholdViewModel';
        ko.mapping.fromJS(data, mapping, this);
    
        this.T12 = ko.computed(function () {
            var total = 0;
            if (!this.Accounts) { return 0; }
            ko.utils.arrayForEach(this.Accounts(), function (account) {
                total += account.T12Revenue();
            });
            return total;
        }, this);
    };
    

    Add the if statement in there to return nothing (or whatever you want) incase that this.Accounts does not exist.