Reputation: 2294
For some reason I cannot seem to get a ko.computed observable to compute when the associated value changes.
This is an object which represents a single reward points record for a customer
//
// RewardPoints Model
var RewardPointsItemModel = function (data) {
return {
DateAwarded: ko.observable((data != null) ? data.DateAwarded : ""),
Points: ko.observable((data != null) ? data.Points : 0)
}
};
I define a single viewModel which houses a reference to an "OrderDetailModel". This OrderDetailModel has a single property defined as a ko.observable and is initialized with an instance of a new, empty OrderDetailModel; initialized with an empty array, and applied to the approprite section of HTML dentified by the "$OrderDetailForm" reference.
$j(function () {
//
// initialize global DOM references
$LoyaltyProgram = $j("#LoyaltyProgram");
$LoyaltyHistory = $j("#LoyaltyHistory");
$OrderDetailForm = $j("#OrderDetailForm");
//
// define and bind the viewModels
viewModel = {
OrderDetailModel: {
OrderDetail: ko.observable( new OrderDetailModel([]) )
}
};
ko.applyBindings(viewModel.LoyaltyHistoryOrderDetailModel, $OrderDetailForm[0]);
});
Here is the definition of the "OrderDetailModel" object. It takes an array of RewardPointsItemModel object instances (defined above) as the initialization parameter "data". Ultimately what this does is maintains an array of RewardPointsItemModels and computes the sum of the Points property of each of the RewardPointsItemModels. When the page is first loaded an instance of this is created with an empty array (see above) resulting in a computed "TotalPoints" of 0 (zero).
//
// OrderDetail Model
function OrderDetailModel(data) {
var self = this;
this.RewardPoints = ko.observableArray(data);
this.TotalPoints = ko.computed(function () {
var points = 0;
if (self.RewardPoints.length <= 0)
return points;
for (var i = 0; i < self.RewardPoints().length; i++) {
var record = self.RewardPoints()[i];
points += record.Points();
}
return points;
});
};
User interaction executes a call to a WebAPI service that returns a list of reward points records, then passes that data to the callback function below as the "data" argument. In the callback function, I create a new, empty array, then populate it with instances of the RewardPointsItemModel objects created from the records retreived from the WebAPI call. I then replace the empty array value in the ko.observableArray property "RewardPoints" in the existing instance of the OrderDetailModel which is stored in the ko.observable property ... viewModel.OrderDetailModel.OrderDetail ... with my new rewardPoints array.
function Callback(data) {
var rewardPoints = new Array();
for (var i = 0; i < data.ServiceModel.length; i++) {
var model = new RewardPointsItemModel(data.ServiceModel[i]);
rewardPoints.push(model);
}
viewModel.OrderDetailModel.OrderDetail().RewardPoints(rewardPoints);
};
At this point I expect the ko.computed observable property "viewModel.OrderDetailModel.OrderDetail().TotalPoints()" to recompute, but when I put tracking code in it in the computed function it doesn't even get called which indicates that the function is not executing to update the value. It is my understanding that if the dependency property, in this case RewardPoints, were updated (from empty Array to populated array) that the computed property should re-evaluate.
I know that this has been complicated for me to explain so I hope that I have been clear. I am hoping there is someone more fluent in Knockout than I am that can understand this clearly and find out why the computed values are not computing after initialization.
Upvotes: 1
Views: 1656
Reputation: 114792
It looks like your problem is here:
if (self.RewardPoints.length <= 0)
return points;
You need to do:
if (self.RewardPoints().length <= 0)
return points;
self.RewardPoints
is an observableArray
, which is a function. The length of a function is the number of arguments defined for the function. An observableArray
does not list any named args, as it reads it from arguments, so the value is 0.
So, your current code is always returning 0 and not actually accessing the value of the observableArray
to create a dependency.
Upvotes: 3