Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using ko.utils.arrayForEach to iterate over a observableArray

I am trying to calculate sum of 'price' field of an 'observableArray'. I have the following code so far:

(function(){

function objFeatures(name,price) {
        return {
            name: ko.observable(name),
            price: ko.observable(price),

            removeFeatures: function () {
                appViewModel.features.remove(this);
            }
        }
    }

var appViewModel = {
features: ko.observableArray([
            new objFeatures("Feature1", 20),
            new objFeatures("Feature2", 20)
        ]),

 grandTotal: ko.computed(function () {
            var total = 0;
            ko.utils.arrayForEach(this.features(), function () {
                total += this.price();
            })
            return total;
        })
};

ko.applyBindings(appViewModel);

}());

When I try to run this, i get an "Error: this.features is not a function" in the firebug console.

What am i doing wrong?

like image 789
nthapa Avatar asked Feb 19 '12 18:02

nthapa


People also ask

What is Ko observableArray?

If you want to detect and respond to changes of a collection of things, use an observableArray . This is useful in many scenarios where you're displaying or editing multiple values and need repeated sections of UI to appear and disappear as items are added and removed.

How do you update items in observableArray knockout?

You should look at defining the object structure for each element of your array and then add elements of that type to your observable array. Once this is done, you will be able to do something like item. productQuantity(20) and the UI will update itself immediately. EDIT Added the function provided by the OP :).

How do I sort knockout observable array?

Description. The KnockoutJS Observable sort() method sorts all items in the array. By default, items are sorted in an ascending order. For sorting an array in a descending order, use reverse() method on sorted array.


1 Answers

Computed observables are evaluated immediately during creation. In your case, appViewModel has not been created yet and this will not represent the appViewModel.

There are many ways to ensure that this is correct in this case. Here are two:

  1. Create it outside of your initial object literal:

    var appViewModel = {
       features: ko.observableArray([
           new objFeatures("Feature1", 20),
           new objFeatures("Feature2", 20)
           ])
    };
    
    appViewModel.grandTotal = ko.computed(function() {
        var total = 0;
        ko.utils.arrayForEach(this.features(), function(feature) {
            total += feature.price();
        });
    
        return total;
    }, appViewModel);
    
  2. Create your view model in a function:

    var AppViewModel = function() {
        this.features = ko.observableArray([
            new objFeatures("Feature1", 20),
            new objFeatures("Feature2", 20)
        ]);
    
        this.grandTotal = ko.computed(function() {
            var total = 0;
            ko.utils.arrayForEach(this.features(), function(feature) {
                total += feature.price();
            });
            return total;
        }, this);
    };
    
    ko.applyBindings(new AppViewModel());​
    
like image 133
RP Niemeyer Avatar answered Oct 08 '22 10:10

RP Niemeyer