Reputation: 6020
I have an array of questions in my model, with the following attributes:
I'm using ko.mapping
to bind a JSON string (of which I'm retrieving from an asmx web method) to my view model.
I have a bunch of primary questions that have no parents
or activators
as these should always be visible, then a bunch of dependent questions that depend on their respective parent(s) having a certain value before the dependent is visible. This can extend as far as depdendents being dependent on dependents (if you see what I mean).
My initial thought (as I'm slowly getting there with knockout.js) was to subscribe to the answer
property of my question
and then grab a sub-set of questions that depend on the one just answered. Then have a look at the value, compare them with the activators and show / hide as necessary.
viewModel.questions().forEach(function (question) {
question.answer.subscribe(function (value) {
var dependents = viewModel.questions().filter(function (q) {
return q.parents() && q.parents().indexOf(question.id()) !== -1;
});
dependents.forEach(function (d) {
if (d.activators() && d.activators().indexOf(value) !== -1) {
d.visible(true);
} else {
d.visible(false);
d.answer(null);
}
});
});
});
While this works, I can't help feeling that I'm missing a trick here. I have to use ko.mapping
to bind the model to my view model as it's already been created for me in the asmx method, so I have to extend my view model (as i'm doing here by cycling through all questions
and subscribing to each one.
Maybe I should be using a ko.computed
for the visible property, or maybe I should be creating some kind of custom ko.bindingHandlers
instead? I'm not sure. What is the correct way of trying to achieve what I want?
Upvotes: 3
Views: 550
Reputation: 417
There are several ways of achieving what you're after, one of them is using custom bindings like you mentioned.
Whether or not that's considered the most "Knockout-correct" way, I won't say, but it's a different approach and might give you some ideas at the very least. Here's one way of creating the binding handler:
ko.bindingHandlers.hideIfIrrelevant = {
update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var question = ko.unwrap(valueAccessor());
if(!question.parents()) {
$(element).show() // Always show the question if it has no parents
return false;
}
var allQuestions = bindingContext.$root.questions();
var parents = allQuestions.filter(function (q) {
return question.parents().indexOf(q.id()) !== -1;
});
var shown = false;
$.each(parents, function(i, parent) {
if(parent.answer() && question.activators().indexOf(parent.answer()) != -1) {
shown = true;
return false;
}
});
if(shown) {
$(element).show();
}
else {
$(element).hide();
}
}
};
Here's the updated fiddle. Note that by using the custom binding, you no longer need the visible
property as part of your data model.
Upvotes: 1