Knockout Observable Array Length always 0
Asked Answered
P

5

9

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);
                                    });
Phoenician answered 21/3, 2013 at 18:47 Comment(0)
P
2

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);
                                    });
Phoenician answered 21/3, 2013 at 20:3 Comment(0)
C
6

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);
Clarence answered 21/3, 2013 at 18:54 Comment(3)
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.Phoenician
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.Phoenician
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.Phoenician
P
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.

Pegram answered 17/5, 2016 at 13:34 Comment(0)
P
2

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);
                                    });
Phoenician answered 21/3, 2013 at 20:3 Comment(0)
D
0

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.

Dioptase answered 21/3, 2013 at 18:56 Comment(1)
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.Phoenician
O
0

Instead of:

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

You should have:

self.contacts(ko.mapping.fromJS(data.data)**()**);
Och answered 7/12, 2016 at 12:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.