Knockout Observable Array Length always 0

10,220

Solution 1

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);
                                    });

Solution 2

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);

Solution 3

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.

Share:
10,220
Strake
Author by

Strake

Updated on June 04, 2022

Comments

  • Strake
    Strake about 2 years

    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);
                                        });
    
  • Strake
    Strake over 11 years
    Implemented both but with no avail. Length remains at 0. I think you are on the right path making it observable and I will keep this change but I still need to resolve the zero length.
  • Strake
    Strake over 11 years
    Interesting and thank you for you input. However this does not pertain to my issue as in past conditional statements I have implemented both double and triple with no trouble. The zero length still exists.
  • Strake
    Strake over 11 years
    This sample does work but it is using .push() rather than ko.mapping.fromJS(). What I tried since forth is the statement self.contacts.push(ko.mapping.fromJS(data.data)); // This gives me a length back. All I need to do now is figure out how that data is nested in contacts.
  • Strake
    Strake over 11 years
    Thank you for your time Roman, this issue has been resolved. The observable had no effect, but it turned out to be .push(). Including this enabled the length of the array to be incremented. I assumed ko.mapping would handle length itself. Question edited with solution and solution posted.