I have a template:
<script id="segment-instructions" type="text/html">
<div data-bind="foreach: Conjunctions">
<!-- Deep hierarchy -->
<p data-bind="visible: !$root.hasAnyValidExpression($data)" />
</div>
</script>
And the following markup where I use it:
<div class="tab-content" id="options-tabs">
...
<div data-bind="template: { name: 'segment-instructions', data: Instructions }"></div>
</div>
This is how I apply the binding:
var instructionsModel = new SegmentInstructionsModel();
...
ko.applyBindings({
GeneralOptions: generalOptionsModel,
Instructions: instructionsModel
}, $('#options-tabs').get(0));
The problem is that $root
in the template is resolved to the object passed to ko.applyBindings
(i.e. the object with GeneralOptions
and Instructions
properties), not to the object specified in the template
binding, which is an instance of my SegmentInstructionsModel
class.
I could solve this in at least two ways, none of which I like:
Keep using $root
in the template, but traversing down to the actual view model rendered by the template
<p data-bind="visible: !$root.Instructions.hasAnyValidExpression($data)" />
I don't like this since the template should not worry about how the object above the actual view model is structured.
Use the $parents
array
<p data-bind="visible: !$parents[$parents.length - 2].hasAnyValidExpression($data)" />
I don't like this for obvious reasons (for one, it stops working once the actual template's view model is passed to ko.applyBinding
)
Is there a way to keep using $root
in a template and not worry about tight coupling of the template with the way its consumer supplies the data to it?
After all, using the $parents
array looks like the way to go, only traversing from the bottom instead from the top (which is not reliable, see above). That is, in my case it would be something like
<p data-bind="visible: !$parents[3].hasAnyValidExpression($data)" />