Search code examples
arraysknockout.jscomputed-observable

Knockout model breaking on array length in computed observable


Slowly extending my nested form at http://jsfiddle.net/gZC5k/1004/ I'm running into a difficulty getting to work ko.computed that I want to use to compute the number of children in the nested JSON array. The code that breaks is at // this breaks

    self.contacts = ko.observableArray(ko.utils.arrayMap(contacts, function (contact) {
    return {
        firstName: ko.observable(contact.firstName),
        lastName: ko.observable(contact.lastName),
        isKey: ko.observable(contact.isKey),
        gender: ko.observable(contact.gender),
        phones: ko.observableArray(ko.utils.arrayMap(contact.phones, function (phone) {
            return {
                type: ko.observable(phone.type),
                number: ko.observable(phone.number),
                calls: ko.observableArray(phone.calls),
                callsVisible: ko.observable(false)
            };
        })),
        addresses: ko.observableArray(contact.addresses),
        optionGender: optionGender,
        phonesVisible: ko.observable(false),
        addressesVisible: ko.observable(false),

// this breaks            
//            numberOfPhones: ko.computed(function (contact) {
//                return contact.phones.length;
//            });
    };
}));

Where is the error?


Solution

  • I think that you're going to need to create each contact as a function:

    var ContactModel = function(contact)
    {
        var self = this;
                self.firstName = ko.observable(contact.firstName);
                self.lastName = ko.observable(contact.lastName);
                self.isKey = ko.observable(contact.isKey);
                self.gender = ko.observable(contact.gender);
               self. phones = ko.observableArray(ko.utils.arrayMap(contact.phones, function (phone) {
                    return {
                        type: ko.observable(phone.type),
                        number: ko.observable(phone.number),
                        calls: ko.observableArray(phone.calls),
                        callsVisible: ko.observable(false)
                    };
                }));
                self.addresses = ko.observableArray(contact.addresses);
                self.optionGender = optionGender;
                self.phonesVisible = ko.observable(false);
                self.addressesVisible = ko.observable(false);
    
                self.numberOfPhones = ko.computed(function () {
                    return self.phones().length;
                });
            return self;
    };
    

    And create it like this:

    self.contacts = ko.observableArray(ko.utils.arrayMap(contacts, function (contact) {
            return new ContactModel(contact);
        }));