KO Controlling descendant bindings.txt.txt
Advanced techniques
In this section, we are going to speak about some advanced techniques. We are not
going to add them to our project because there is no need, but it's good that we know
we can use these methods if our application requires it.
Controlling descendant bindings
If our custom binding has nested bindings, we can tell our binding whether
Knockout should apply bindings or we should control how these bindings will be
applied. We just need to return { controlsDescendantBindings: true } in the
init method.
ko.bindingHandlers.allowBindings = {
init: function(elem, valueAccessor) {
return { controlsDescendantBindings: true };
}
};
www.it-ebooks.info
Chapter 3
[ 69 ]
This code is telling Knockout that the binding called allowBindings is going to
handle all the descendant bindings:
<div data-bind="allowBindings: true">
<!-- This will display 'New content' -->
<div data-bind="text: 'New content'">Original content</div>
</div>
<div data-bind="allowBindings: false">
<!-- This will display 'Original content' -->
<div data-bind="text: 'New content'">Original content</div>
</div>
If we want to extend the context with new properties, we can extend the
bindingContext property with new values. Then we only need to use
ko.applyBindingsToDescendants to update the view-model of its children. Of
course we should tell the binding that it should control the descendant bindings. If
we don't, they will be updated twice.
ko.bindingHandlers.withProperties = {
init: function(element, valueAccessor, allBindings, viewModel,
bindingContext) {
var myVM = { parentValues: valueAccessor, myVar: 'myValue'};
var innerBindingContext = bindingContext.extend(myVM);
ko.applyBindingsToDescendants(innerBindingContext, element);
return { controlsDescendantBindings: true };
}
};
Here we are not creating a child context. We are just extending the parent context. If
we want to create child contexts to manage descendant nodes and have the ability
to use the $parentContext magic variable to access our parent context, we need to
create a new context using the createChildContext method.
var childBindingContext = bindingContext.createChildContext(
bindingContext.$rawData,
null, //alias of descendant item ($data magic variable)
function(context) {
//manage your context variables
ko.utils.extend(context, valueAccessor());
});
ko.applyBindingsToDescendants(childBindingContext, element);
return { controlsDescendantBindings: true }; //Important to not
bind twice
www.it-ebooks.info
Custom Bindings and Components
[ 70 ]
Now we can use the magic variables inside our child nodes:
<div data-bind="withProperties: { displayMode: 'twoColumn' }">
The outer display mode is <span data-bind="text:
displayMode"></span>.
<div data-bind="withProperties: { displayMode: 'doubleWidth' }">
The inner display mode is <span data-bind="text:
displayMode"></span>, but I haven't forgotten
that the outer display mode is <span data-bind="text:
$parentContext.displayMode"></span>.
</div>
</div>
By modifying binding contexts and controlling descendant bindings, you have a
powerful and advanced tool to create custom binding mechanisms of your own.