Reputation: 12420
I have the following javascript that does my knockout binding.
var context = this;
var viewModel = {
lineitems: [{
quantity: ko.observable(1),
title: 'bar',
description: 'foo',
price: ko.observable(10),
total: ko.observable(10),
formattedTotal: ko.computed({
read: function () {
return '$' + this.price().toFixed(2);
},
write: function (value) {
value = parseFloat(value.replace(/[^\.\d]/g, ""));
this.price(isNaN(value) ? 0 : value);
}
})
}]
};
ko.applyBindings(viewModel);
Which binds as expected, however when I apply the formattedTotal, I get the following javascript error.
Uncaught TypeError: Object [object global] has no method 'price'
I've tried a few changes to the syntax, but I can't seem to get it right, where am I going wrong?
Upvotes: 1
Views: 289
Reputation: 10328
The problem is inside your formattedTotal
method: the scope - this
- is not your viewModel. Try this:
var viewModel = {
lineitems: [{
quantity: ko.observable(1),
title: 'bar',
description: 'foo',
price: ko.observable(10),
total: ko.observable(10),
formattedTotal: ko.computed({
read: function () {
return '$' + viewModel.lineitems.price().toFixed(2);
},
write: function (value) {
value = parseFloat(value.replace(/[^\.\d]/g, ""));
viewModel.lineitems.price(isNaN(value) ? 0 : value);
}
})
}]
};
Consider using a constructor function for your viewmodels instead of an object literal; this makes dealing with scope issues easier and cleaner. See this answer for an example.
Upvotes: 1
Reputation: 3517
Usually it is not a best idea to use this
in JavaScript. Especially with Knockout. You never know what this
will be during execution.
So I recommend writing it this way:
function LineItem(_quantity, _title, _description, _price) {
var self = this;
self.quantity = ko.observable(_quantity);
self.title = ko.observable(_title);
self.description = ko.observable(_description);
self.price = ko.observable(_price);
self.total = ko.computed(function () {
return self.price() * self.quantity();
}, self);
self.formattedTotal = ko.computed(function () {
return '$' + self.total().toFixed(2);
}, self);
};
var viewModel = {
lineItems: [
new LineItem(10, 'Some Item', 'Some description', 200),
new LineItem(5, 'Something else', 'Some other desc', 100)
]
};
ko.applyBindings(viewModel);
You can read some discussion about self=this
pattern here.
Upvotes: 1