I'm using v 1.10.3 of HC and I'm trying to extend the ViewModel for the drilldown view. I want to add a new boolean property to the products so that I can check it and add some html to the view as necessary. So inside of Category.js I thought I'd loop through the data, and add the new property to the ViewModel so that it could be used in the View. The loop is where I'm having a problem. When I debug the code, the loop adds the property as expected, but when the page finishes loading and I check the source, none of the modifications are present in the Json object.
function HcDrillDownFilterViewModel(data, $form, catId, modId) {
var DECIMAL_SEP = ".";
var self = this;
for (var i = 0; i < data.Products.length; i++) {
var p = data.Products[i];
if (p.ProductName.toLowerCase().indexOf('nike') > -1) {
p.NikeBrand = true;
} else {
p.NikeBrand = false;
}
}
// Binding
self.model = ko.observable();
self.minPrice = ko.observable(data.SelectedMinPrice);
self.maxPrice = ko.observable(data.SelectedMaxPrice);
Any ideas on what I'm missing to get these changes to persist to the ViewModel?
What you're running into is simply a tiny learning curve with how KnockoutJS works. Since it's a framework with a lot of bindings and other things working, you need to work with it. Oftentimes, this means a raw JS snippet may not work as expected.
To be honest, I rarely touch this view myself, because I'm not very well versed in KO either, but I managed to get a proof of concept working based upon your question.
First, in your code, you're updating the array objects, but you're only updating it in one of the places that binds to the view. It needs to be done in two places. This is the primary reason you don't see your updates applied.
In place of your original snippet, I've put this call to a method I created in the same JS file.
// update Products how you'd like
data.Products = parseProducts(data.Products);
Then, I did the same in the top of the handleDrillDown()
function.
// this needs to get called here too
data.Products = parseProducts(data.Products);
Now, there may be a better way to do this, but the final update in this file did all the work by adding the function you see below. In my case, I used the sample products that come out-of-the-box and simply checked for the Brown Fedora. You'll also notice that I'm using the built-in foreach that Knockout provides. You should do this whenever using a framework.
function parseProducts(products) {
// instantiate a local array of products to work with
var arrProducts = products;
// loop through and apply your changes
ko.utils.arrayForEach(arrProducts, function (p) {
// check your condition
if (p.ProductName.toLowerCase().indexOf("fedora") > -1) {
p.CoolHat = true; // new property that wasn't there before
} else {
p.CoolHat = false; // new property that wasn't there before
}
});
// send back the new array
return arrProducts;
}
Finally, I updated the drilldown Razor view markup to see if my changes were reflected as I expected, by adding this snippet after the product name.
<span data-bind="if: CoolHat" style="font-weight:bold; color: red;">This is a really cool hat!</span>
The result was that only the Fedora was getting "tagged" with this text.