Consider the following ViewModel that is generated through the knockout mapping plugin.
var originalData = {
"QuoteSelectedViewModel": {
"ProductName": "Select",
"CoverQuotesViewModel": [
{
"Code": 1,
"Label": "Première Assistance 24h/24 (GRATUITE)",
"IsMandatory": true,
"IsSelected": true,
"DependsOn": []
},
{
"Code": 2,
"Label": "Assistance PLUS 24h/24",
"IsMandatory": false,
"IsSelected": false,
"DependsOn": []
},
{
"Code": 8,
"Label": "Heurts Animaux / Force de la Nature",
"IsMandatory": false,
"IsSelected": false,
"DependsOn": [
2
]
},
]}
}
var viewModel = ko.mapping.fromJS(originalData);
ko.applyBindings(viewModel);
<div data-bind="with: QuoteSelectedViewModel">
selected quote is : <span data-bind="text: ProductName"></span>
<!-- ko foreach: CoverQuotesViewModel -->
<br/>
<div data-bind: if: IsVisible>
<input type="checkbox" data-bind="checked: IsSelected"></input>
<input type="text" data-bind="value: Label, enable: IsSelected"></input>
</div>
<!-- /ko -->
</div>
Now, I would like to hide the div when IsVisible returns false. IsVisible does not exist yet, and it should be a computed observable function on each element of the CoverQuotesViewModel array.
How do I generate this computed observable function on each element ?
Thanks
[EDIT] I've added a jsfiddle here : http://jsfiddle.net/graphicsxp/fpKWM/
[EDIT2] Actually knockout document is clear about how to do that:
Of course, inside the create callback you can do another call to ko.mapping.fromJS if you wish. A typical use-case might be if you want to augment the original JavaScript object with some additional computed observables:
var myChildModel = function(data) { ko.mapping.fromJS(data, {}, this);
this.nameLength = ko.computed(function() { return this.name().length; }, this); }
[EDIT]
Here's the full code following Paul's suggestion: (getQuotesSuccess is an AJAX success handler)
viewModel.getQuotesSuccess = function (result) {
var myCoverQuotesViewModel = function (data, parent) {
var self = this;
ko.mapping.fromJS(data, {}, this);
self.IsVisible = ko.computed(function () {
var visible = true;
if (self.DependsOn().length > 0) {
$.each(self.DependsOn(), function (index, value) {
var dependency = viewModel.QuoteSelectedViewModel().CoverQuotesViewModel.filterByProperty("Code", value);
if (dependency().length > 0) {
visible = visible & dependency()[0].IsSelected();
} else {
visible = false;
}
});
}
return visible;
}, this);
}
var mapping = {
'CoverQuotesViewModel': {
create: function (options) {
return new myCoverQuotesViewModel(options.data, options.parent);
}
}
}
ko.mapping.fromJS(result, mapping, viewModel);
};
Ok, reverting back to my earlier answer, with your modifications, so anyone else looking at this answer actually gets the correct version!
You need to create a child viwe model, and use the mapping plugin to populate it automatically, then add in your computed observable:
Then you need to use a create map for the mapping of the main view model, and in this you create your child view model:
You don't need to pass
this
into the computed, as you are referencing self, which is your stored version of this.