Strake Strake - 6 months ago 124
HTML Question

Knockout Observable Array Length always 0

When calling the length of any observable in the customerOverview view model I receive a length of zero. There is data present in the observables as the bindings update with data, however the length remains at 0. The base view model, 'CustomerCentral', returns lengths properly. I need the length of some observables in 'CustomerOverview' to do some conditional statements.

HTML Bindings



<ul class="nav nav-list">
<li class="nav-header">Contacts</li>
<!--ko if: customerOverview.contacts().length == 0-->
<li>No contacts associated with this customer</li>
<!-- /ko -->
<!--ko foreach: customerOverview.contacts()-->
<li>
<a data-bind="click: $root.customerOverview.viewContact"><i class="icon-chevron- right single pull-right">
</i><span data-bind="text: FirstName"></span><span data-bind="text: LastName"></span>
</a></li>
<!-- /ko -->
</ul>


JS



function CustomerOverview() {
var self = this;

self.contacts = ko.observableArray([]);

self.getCustomerContacts = function () {
requestController = "/CRM/CustomerCentral/CustomerContacts";
queryString = "?id=" + self.customer().Id();
$.ajax({
cache: false,
type: "GET",
dataType: "json",
url: baseURL + requestController + queryString,
headers: { "AuthToken": cookie },
success:
function (data) {
if (data.data.length > 0) {

self.contacts(ko.mapping.fromJS(data.data));

console.log(self.contacts().length);
}
}
});
};
};
function CustomerCentral() {

var self = this;

self.customerOverview = ko.observable(new customerOverview());
};

var vm = new CustomerCentral();
ko.applyBindings(vm);


Console cmd: vm.customerOverview().contacts().length
0

---------------------------SOLUTION ---------------------- observableArray.push()

The issue turned out to be this line :

self.contacts(ko.mapping.fromJS(data.data));


SOLUTION:
Adding .push() to this enabled the length property of the array to be incremented. I had assumed ko.mapping would handle this but it does not. Changing the variable to observable had no effect.

$.each(data.data, function () {
self.contacts.push(ko.mapping.fromJS(this));
console.log(self.contacts().length);
});

Answer

I think your problem is not having your customerOverview property as observable

try:

 self.customerOverview = ko.observable(new CustomerOverview());

or

 self.customerOverview = ko.computed(function(){
       return new CustomerOverview();
 });

Working sample:

http://jsfiddle.net/dvdrom000/RHhmY/1/

html

<span data-bind="text: customerOverview().contacts().length"></span>
<button data-bind="click: customerOverview().getCustomerContacts">Get contacts</button>

js

function CustomerOverview() {
        var self = this;        

        self.contacts = ko.observableArray([]);           

        self.getCustomerContacts = function () {
            self.contacts.push(1);
            self.contacts.push(2);
            self.contacts.push(3);            
        };
};
   function CustomerCentral() {

        var self = this;
        // Is this a correct way. Am I breaking something with this?
        self.customerOverview = ko.observable(new CustomerOverview());
};

var vm = new CustomerCentral();
    ko.applyBindings(vm);