Working with KnockOut - I'm trying to build the basics of a master detail/items app before adding to MVC .Net code.
All I want to do is have a simple item, price, tax - and for a computed column to show the amount including tax for each item:
The client side KnockOut viewmodel is:
var GiftModel = function(gifts) {
var self = this;
self.gifts = ko.observableArray(gifts);
self.formattedPrice = ko.computed(function() {
var pricet = self.gifts().price;
return pricet ? "$" + pricet.toFixed(2) * (1 + self.gifts().tax : "None";
});
self.addGift = function() {
self.gifts.push({
name: "",
price: "",
tax:0
});
};
self.removeGift = function(gift) {
self.gifts.remove(gift);
};
self.save = function(form) {
alert("Could now transmit to server: " + ko.utils.stringifyJson(self.gifts));
// To actually transmit to server as a regular form post, write this: ko.utils.postJson($("form")[0], self.gifts);
};
};
var viewModel = new GiftModel([
{ name: "Tall Hat", price: "39.95", tax:17.5},
{ name: "Long Cloak", price: "120.00", tax:20}
]);
ko.applyBindings(viewModel);
// Activate jQuery Validation
$("form").validate({ submitHandler: viewModel.save });
The table markup is:
<table data-bind='visible: gifts().length > 0'>
<thead>
<tr>
<th>Gift name</th>
<th>Price</th>
<th>Tax</th>
<th />
</tr>
</thead>
<tbody data-bind='foreach: gifts'>
<tr>
<td><input class='required' data-bind='value: name, uniqueName: true' /></td>
<td><input class='required number' data-bind='value: price, uniqueName: true' /></td>
<td><input class='required number' data-bind='value: tax, uniqueName: true' /></td>
<td data-bind='text: formattedPrice'></td>
<td><a href='#' data-bind='click: $root.removeGift'>Delete</a></td>
</tr>
</tbody>
</table>
<button data-bind='click: addGift'>Add Gift</button>
<button data-bind='enable: gifts().length > 0' type='submit'>Submit</button>
It's stalling as the formattedPrice function doesnt appear to be working.
I've got it in a jsfiddle here: http://jsfiddle.net/marktait/TR6Sy/ - would anyone be able to help me get over this seemingly simple hurdle?
Thank you,
Mark
The problem is that you are calling the comouted function while looping on the list of gifts. However, the computed method is not available for a given gift, but for all gifts. You have two choices:
Either you make it so that each gift object is an object with this computed method (like user Brandon suggested), or you just transform it to a normal function that takes as a parameter a gift, like this:
self.getFormattedPrice = function(price, tax) {
var val = price ? "$" + parseFloat(price).toFixed(2) * (1 + tax) : "None";
return val;
};
And then, you call it like this:
<td data-bind='text: $parent.getFormattedPrice(price, tax)'></td>
I've updated your fiddle.
self.gifts() is an array. But in your computed, you are trying to use it as a single value. That just won't work. You need to add it as a computed property to each item in the array:
var addFormattedPrice = function (gift) {
gift.formattedPrice = ko.computed(function () {
var pricet = gift.price;
return pricet ? "$" + pricet.toFixed(2) * (1 + gift.tax : "None";
});
};
ko.utils.arrayForEach(self.gifts(), addFormattedPrice);
self.addGift = function() {
var gift = {
name: "",
price: "",
tax:0
};
addFormattedPrice(gift);
self.gifts.push(gift);
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With