KnockoutJS - component Binding


Advertisements

This binding is used to insert a component into DOM elements and pass the parameters optionally. This binding can be achieved in the following two ways −

  • Shorthand Syntax
  • Full syntax

Shorthand Syntax

In this approach only the component name is specified without specifying any parameters.

Syntax

<div data-bind = 'component: "component-name"'></div>

The parameter value passed can be an observable. Hence, whenever the observable changes, the old component instance will be disposed and the new one will be created according to the refreshed parameter value.

Full syntax

This approach accepts the parameter in the form of an object.

Syntax

<div data-bind = 'component: {
   name: "component-name",
   params: { param1: value1, param2:value2 ...}
}'></div>

The object is made up of the following two items −

  • name − This is the name of the component to be inserted. As mentioned earlier, this can be an observable.

  • params - This is an object to be passed to the component. Mostly, this will be a key-value object including multiple parameters. This is most of the times received by the constructor of a ViewModel.

Component Processing Workflow

The following diagram explains the process that takes place when a component is injected by component binding.

component lifecycle

Let us look at the process in detail −

Receive ViewModel factory and template from component loaders − TThe registered ViewModel and template is requested and received by the default loader. By default, this is an asynchronous process.

Clone the component template − In this step, cloning of component template and inserting it into DOM element takes place. Existing content, if any, will be removed.

Instantiate a ViewModel if any − In this step, ViewModel is instantiated. If the ViewModel is provided as a constructor function, then KO calls.

new ViewModelName(params)

If the ViewModel is provided in factory function format, i.e. createViewModel then KO calls.

createViewModel(params, yourcomponentInfo)

Here yourcomponentInfo.element is the element where the template is inserted.

Bind ViewModel to view − In this stage, ViewModel is bound to View. If the ViewModel is not provided, then binding is done with parameters mentioned in component binding.

Now component is ready − At this stage, the component is ready and in functioning form. The component keeps an eye on the parameters which are observable, if any, so as to write the changed values.

Dispose the ViewModel if the component is lost − The ViewModel's dispose function is called, if the component binding name value is changed observably or some control-flow binding removes the DOM element container itself, which was meant to hold the component output. The dispose takes place just before any element container is removed from DOM.

Example

Let us take a look at the following example which demonstrates the use of component binding.

<!DOCTYPE html>
   <head>
      <title>KnockoutJS Component binding</title>
      <script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.3.0.js"
         type = "text/javascript"></script>
   </head>
   
   <body>
      <h4>Component binding without parameters</h4>
      <div data-bind = 'component: "calculate-sum"'></div>

      <h4>Component binding passing parameters</h4>
      <div data-bind = 'component: {
         name: "calculate-sum",
         params: { number1: 2, number2: 3 }
      }'></div>

      <script>
         ko.components.register('calculate-sum', {
            
            viewModel: function(params) {
               this.number1 = ko.observable(params && params.number1);
               this.number2 = ko.observable(params && params.number2);

               this.result = ko.computed(function() {
                  var sum = Number(this.number1()) + Number(this.number2());
                  if ( isNaN(sum) )
                  sum = 0;
                  return sum;
               },this);
            },
            
            template: 'Enter Number One: <input data-bind = "value: number1" /> <br> <br>'+
               ' Enter Number Two: <input data-bind = "value: number2" /> <br> <br>'+
               ' Sum  = <span data-bind = "text: result" />'
         });

         ko.applyBindings();
      </script>
      
   </body>
</html>

Output

Let's carry out the following steps to see how the above code works −

  • Save the above code in component-bind.htm file.

  • Open this HTML file in a browser.

  • Enter the numbers in both textboxes and observe that the sum is calculated.

Observations

Template Only Components

Components can be created without ViewModel. The component can just comprise of a template shown as follows.

ko.components.register('my-component', {
   template: '<div data-bind = "text: productName"></div>'
});

And DOM will look like −

<div data-bind = 'component: {
   name: "my-component",
   params: { productName: someProduct.name }
}'></div>

Using Component binding without DOM container element

There might be situation where it is not possible to insert a component into DOM element. Essential binding can still be performed with the help of container-less syntax based on the comment tags shown as follows.

The <!--ko--> and <!--/ko--> works as start and end markers making it a virtual syntax and binds the data as if it is a real container.

Memory management and Disposal

Disposal function can be added optionally as part of ViewModel. If this function is included, then it will be invoked whenever the component is lost or the container element itself is removed. It is a good practice to use dispose function to release resources occupied by unwanted objects, which are not garbage collectable by default. Following are a few examples −

  • setInterval method will keep on running until cleared explicitly. clearInterval (handle) is used to stop this process.

  • ko.computed properties need to be disposed explicitly. Else, they might still continue receiving notifications from their underlying observables. Manual disposal can be avoided using pure computed functions.

  • Make sure to use dispose() method on the subscription, else it keeps on firing the changes until disposed.

  • Custom event handlers created on DOM elements and created inside createViewModel needs to be disposed.

knockoutjs_declarative_bindings.htm
Advertisements