Search code examples
knockout.jsko.observablearray

0 length ObserveableArray when accessed inside function


I have a model class with a few functions (methods) attached to it. When I look at the length of an observable array outside of the functions the length is returned correctly. But when I look at the observablearray inside a function of the modelclass it always returns 0. But if I access an item inside the observablearray by index inside the function it returns the correct item. Why would length always be 0?

    function ModelView(data) {
      var self = this;


      self.items= ko.observableArray(data.items);
      var test = self.items().length; //shows correct number
      self.EditRule = function (product) {
        for(var i=0; i<self.items().length; i++)
              //dosuff but self.items().length is always 0


      }
    }

I found a work around by adding an additional property into the viewmodel like so:

     self.itemslength = ko.observable(self.items().length);

obviously my actual issue is much more complicated but the loop is doing a compare of items against parameters passed in to make sure somethings are valid. self.items is basically a masterlist.


Solution

  • try using ko.utils.arrayForEach for iterating over your observableArray:

    function ModelView(data) {
          var self = this;
          self.items = ko.observableArray(data.items);
          var test = self.items().length; //shows correct number
          self.EditRule = function () {
              ko.utils.arrayForEach(self.items(), function(item){
                  if (item.name === "2"){
                      // For example
                      console.log(self.items().length); //will be 3
                      self.items.remove(item);
                      console.log(self.items().length); //will be 2
                  }
              });
          }
     }
    
    var myData = {
        items : [{id: 0, name: "0"},{ id: 1, name: "1"}, {id: 2, name: "2"}]
    }
    
    var myModelView = new ModelView(myData);
    ko.applyBindings(myModelView);
    

    with this html i tested:

    <ul data-bind="foreach: items">
        <li data-bind="text: name"></li>
    </ul>
    <a href="#" data-bind="click: EditRule">EditRule</a>
    

    You can also use the vanilla for loop if you like: Its very similar to your own attempt but you might have a mistake somewhere else.

    function ModelView(data) {
          var self = this;
          self.items = ko.observableArray(data.items);
          var test = self.items().length; //shows correct number
          self.EditRule = function () {
              for(var i =0; i < self.items().length; i++){
                  if (self.items()[i].name === "2"){
                      // For example
                      console.log(self.items().length); //will be 3
                      self.items.remove(self.items()[i]);
                      console.log(self.items().length); //will be 2
                  }
              }
          }
     }