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);
});
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);
});
Share
Improve this question
edited Dec 9, 2013 at 16:46
Strake
asked Mar 21, 2013 at 18:47
StrakeStrake
7621 gold badge9 silver badges18 bronze badges
5 Answers
Reset to default 6I 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);
Knockout provides a set of manipulation functions for arrays that mirror the functions found in in JavaScript; pop, push, shift, unshift, reverse, sort, and splice. Along with performing the operations you’d expect, these array functions will also automatically notify any observers that the array has changed. The JavaScript methods wont. If you want your UI to update when the array counts change, you’ll want to be careful to use the Knockout functions.
Reference: http://ryanrahlf.com/knockout-js-observablearray-not-updating-the-ui-heres-how-to-fix-it/
So basically, to solve your problem, you just need to use the knockout push function directly on the observable array instead of using the javascript push method. Hence:
Change this:
self.contacts( ).push( data.data );
By this:
self.contacts.push( data.data );
And you will be able to use the contacts( ).length property on your html and be notified on every change in the array.
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);
});
I had problems like this, and IIRC, it was because I was using double equals (==) instead of triple equals (===) in the comment conditionals. Give it a shot.
Instead of:
self.contacts(ko.mapping.fromJS(data.data));
You should have:
self.contacts(ko.mapping.fromJS(data.data)**()**);