In my previous articles (Part I, II, III and IV), we explained the bindings in KnockoutJS. In this article, we will see the various binding contexts available in Knockout Binding.
What is Binding Context?
Binding Context in KnockoutJS is an Object that holds the data (viewmodel's properties and functions) from your binding. This binding context will be created when the binding is applied using "ko.applyBindings". We can access these binding contexts using the special reference properties provided by KO.
There are the following 8 binding contexts available in KnockoutJS:
- $parent
- $parents
- $root
- $data
- $index
- $parentContext
And the following are two more special properties:
- $context
- $element
We will discuss these one by one.
The $root Binding context
The $root binding context is the root context that is the main viewmodel.
// $root context here
<p data-bind="with: rootBinding">
Welcome to <span data-bind="text: $root.title + ' ' + name()"></span>
</p>
// ViewModel
var RootBinding = function () { this.name = ko.observable('Jagan'); };
var viewModel = {
title: 'Binding Context In KnockoutJS',
rootBinding: new RootBinding()
};
ko.applyBindings(viewModel);
In this above viewmodel, the $root binding context will have the "viewModel" object since we have applied the binding with that object. As we used the with
binding handler, it will create a new binding context for the <p> element. To access the title in the <p>, we need to use the $root context property.
The $data Binding context
The $data binding context is the current context. The $data binding will have the data applied to the current context. The $data binding context will be used most in the foreach binding. For example, we will use the $root example as in the following:
// $root context here
<div data-bind="with: dataBinding">
// $parent context here
<div data-bind="foreach: fruits">
<span data-bind="text: $data.fruit"></span> // $data context here
</div>
</div>
In this example, we have a div with a span to display the fruit name. The div is bound with the foreach binding handler, so that it will repeat the rendering of the span with the text. The fruits property is an array of objects, to access the object (current context) inside the foreach, we are using the $data binding context property.
Note: In the $root context, the $data context will have the main viewmodel, in other words the $root and $data context is the same if you access the $data in the $root context.
The $index Binding context
The $index binding context gives you the integer value, in other words the index of the current item in the foreach binding. We slightly modified the $data example for $index as in the following:
// $root context here
<div data-bind="with: indexBinding">
// $parent context here
<div data-bind="foreach: fruits">
<span data-bind="text: $index() + ')' + $data.fruit + ' '"></span> // $data context here
</div>
</div>
In this example, the $index binding context property gets the index of the current item. The $index binding context property is an observable and it will be updated whenever an item is added or removed or an item is moved to associated array or observableArray.
The $parent Binding context
The $parent binding context is the immediately outer context for the current context. In the $root context, the $parent context will be undefined because there won't be any parent for the root view model.
//$root context or $parent context for $data context
<p data-bind="with: rootBinding">
Welcome to <span data-bind="text: $parent.title + ' ' + $data.name()"></span> //$data context
</p>
We can use the $root example here, the immediate parent for the <p> element binding context is $root context. The $root context is the $parent context for the $data context.
The $parents Binding context
The $parents binding is the collection/array of the parents from the $data binding context.
// $root context here
<div data-bind="with: parent2"> // $parent 2 context here
<div data-bind="with: parent1"> // $parent 1 context here
<div data-bind="with: parent0"> // $parent 0 context here
<div data-bind="with: childBinding"> // $data context here
<span data-bind="text: $parents[0].text"></span> <br />
<span data-bind="text: $parents[1].text"></span> <br />
<span data-bind="text: $parents[2].text"></span> <br />
<span data-bind="text: $data.text"></span>
<span data-bind="text: $root.title"></span>
</div>
</div>
</div>
</div>
// View model
parent2: {
text: 'This is parent 2',
parent1: {
text: 'This is parent 1',
parent0: {
text: 'This is parent 0',
childBinding: {
text: 'This is child'
}
}
}
}
In this above example, we are accessing the text property from the parents using the $parents binding context.
The $parentContext Binding context
The $parentContext binding context is a reference of the parent context. The $parent context holds the data of the parent context whereas the $parentContext holds the $data context of the $parent context.
The $parentContext binding context is useful when you have a nested foreach binding as in the following:
<div data-bind="with: parentContextBinding">
<div data-bind="foreach: items">
<div data-bind="foreach: innerItems">
<span data-bind="text: $parentContext.$index() + '.' + $index() + ')' + $data + '->' + $parentContext.$data.text "></span>
</div>
</div>
</div
// View model
parentContextBinding: {
items: [
{ innerItems: [1, 2, 3], text: 'one' },
{ innerItems: [1, 2, 3], text: 'two' },
{ innerItems: [1, 2, 3], text: 'three' }]
}
The outer foreach is bound with the items array. The items array contains three objects. Each object of an items array contains an array of integers and a text property. The innerItems array is bound with the inner foreach.
In the preceding example:
- The $parentContext.$index will provide you the index of the current item in the items array.
- The $parentContext.$index is equal to $index in the outer foreach binding context.
- The $parentContext is equal to $data in the outer foreach binding context.
- The $parentContext.$data.text will provide the text property value of the current item in the items array.
The $context and $element property
The $context property will have the current context object. It is useful when you want to manipulate some data on the current elements context from the viewmodel.
The $element property will expose the attributes available for the current element.
<div data-bind="with: properties">
<p><b>The $context and $element properties</b></p>
<p> <span id="spanCtrl" data-bind="text: 'Span Id is :' + $element.id"></span> </p>
<span data-bind="text: $context.$data.title"></span>
</div>
If you see the output of this markup then the span that contains the $element.id, printed the id of the span element and the span that contains the $context.$data.title, printed the value of the title property.
Note: The $context is not equal to $data but it will hold the $data context.
It was difficult for me to explain the binding context however I can explain it. If you feel it is difficult then please just drop a comment.
The complete example for the binding context is given below with source.
Happy Coding :)