user1480815
user1480815

Reputation: 41

knockout not auto updated computed value

function for Violation:

function Violation(violCd, desc, amt) {
        this.violCd = ko.observable(violCd);
        this.desc = ko.observable(desc);
        this.amtToPay = ko.observable(amt);
    }

View Model:

 self.violations = ko.observableArray([]);

 self.addViol = function () {
      alert('adding');
      self.violations.push(new Violation({ violCd: "28-0000", desc: "DUI OR SOMETHING",
     amtToPay: "300" }));
}
self.total = ko.computed(function () {
      alert(total);
      var total = 0;
      for (var i = 0; i < self.violations.length; i++) {
           total += self.violations[i].amtToPay;
      }
      return total;
});

The html is:

<input data-bind="value: total()" />

I need the total to auto update as soon as a violation is added.

Thanks.

Upvotes: 0

Views: 52

Answers (2)

Wayne Ellery
Wayne Ellery

Reputation: 7958

So the main issue is to do with self.violations. This needs to be declared as an observablearray so that if items are added then knockout knows that they have been added and can update the computed total.

self.violations = ko.observableArray();

Then when ever you access the array to get the contents you will need to use self.violations() so your computed function should be:

self.total = ko.computed(function () {
      alert(total);
      var total = 0;
      for (var i = 0; i < self.violations().length; i++) {
           total += self.violations()[i].amtToPay;
      }
      return total;
});

One other issue is that amtToPay is set as a string so in javascript 0 + "300" = "0300". It should be set as an int or float:

self.violations.push(new Violation({ violCd: "28-0000", desc: "DUI OR SOMETHING",
     amtToPay: 300 }));

You could possibly have to also make the properties in Violation as observable as well if it's possible to just modify the value of a property without modifying the array.

eg:

self.violations()[0].amtToPay = 300;

That change won't be noticed by knockout so you would need to declare amtToPay as an observable:

self.amtToPay = ko.observable();

Then to access the value you would need to use self.violations[i]().amtToPay().

If it's input from the user then it would be a string so you would need to convert it to an int or float using parseInt or parseFloat.

Upvotes: 1

user1480815
user1480815

Reputation: 41

I fixed it using this:

        self.violations = ko.observableArray([]);

        self.addViol = function () {

            self.violations.push(new violation({ violCd: "28-0000", desc: "DUI OR SOMETHING", amt: "300" }));
            self.violations.valueHasMutated();

        }
        self.total = ko.computed(function () {
            var total = 0;
            ko.utils.arrayForEach(self.violations(), function (violation) {
                var value = parseFloat(violation.amt());
                if (!isNaN(value)) {
                    total += value;
                }
            });
            return total.toFixed(2);
        });

Now it seems to notice a change.

Upvotes: 0

Related Questions