There are a couple of issues with the "this" scope which are causing problems.
this.subtotal = ko.computed(function () {
return this.count * this.cost;
}).bind(this);
The correct way to get the ambient this scope correct is to pass "this" into the ko.computed as a second argument. Also, count is an observable to you need to evaluate it.
this.subtotal = ko.computed(function () {
return this.count() * this.cost;
}, this);
The products variable is passing "this" into the constructor of product. The ambient this at this point is window, as are you are using anonymous function/revealing module pattern.
So when
this.count = ko.observable(parent.recordCount);
evaluates, parent is window, so recordCount == undefined.
If you want to continue to use the revealing module pattern you need to tweek the order function to declare your return object ("obj") and then create the products.
You should also declare the total property as a ko.computed. I have used map/reduce instead of $.each but that is personal preference.
When this is done, it reveals a further issues with the count property on the product class. The parent.recordCount is an observable, so you are creating an observable where its value is an observable, not the value of the observable. Just assign the observable to a count property.
var product = function (title, operationName, description, parent) {
this.title = title;
this.operationName = operationName;
this.description = description;
this.cost = 9;
this.count = parent.recordCount;
this.subtotal = ko.computed(function () {
return this.count() * this.cost;
}, this);
};
order = function () {
var
listName = ko.observable("not defined"),
listId = ko.observable("not defined"),
recordCount = ko.observable("not defined"),
products = [];
var obj = {
listName: listName,
listId: listId,
recordCount: recordCount,
products: products
}
// now we have an object to push into the product class
products.push(
new product('Product1', 'EMAIL_VER_DELIVERABLE', 'Description.', obj),
new product('Product2', 'EMAIL_BASIC_NO_SUPRESSION_W_VERIFICATION', 'Description.', obj),
new product('Product3', 'PHONE_PREM', 'Description.', obj)
);
obj.total = ko.computed( function() {
return this.products
.map(function(item) { return item.subtotal(); })
.reduce( function(runningTotal, subtotal) { return runningTotal + subtotal;
}, 0);
}, obj);
// anything in the return block is considered public, anything above is private
return obj;
}();
ko.applyBindings(order);
// when this value changes the product Cost needs to be updated
order.listId(1);
order.listName('test list');
order.recordCount(100);