Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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);
                                    });
like image 980
Strake Avatar asked Mar 21 '13 18:03

Strake


2 Answers

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);
like image 127
roman m Avatar answered Oct 16 '22 05:10

roman m


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.

like image 32
José Augustinho Avatar answered Oct 16 '22 06:10

José Augustinho