KnockoutJS - Components

Components are a huge way of organizing the UI code for structuring a large application and promoting code reusability.
It is inherited or nested from other component. For loading and configuration, it defines its own conventions or logic.
It is packaged to reuse throughout the application or the project. Represents the complete sections of application or small controls/widgets. It can be loaded or preloaded on demand.
Components can register using the ko.components.register() API. It helps to load and represent the components in KO. Component name with configuration is expected for registration. The configuration specifies how to determine the viewModel and template.
Syntax
Components can be registered as follows −
ko.components.register('component-name', {
   viewModel: {...},    //function code
   template: {....)	//function code
});
The component-name can be any nonempty string.
The component-name can be any nonempty string.
viewModel is optional, and can take any of the viewModel formats listed in the next sections.
viewModel is optional, and can take any of the viewModel formats listed in the next sections.
template is required, and can take any of the template formats listed in the next sections.
template is required, and can take any of the template formats listed in the next sections.
Following table lists the viewModel formats that can be used to register the components.
constructor function
It creates a separate viewModel object for each component. The object or function is used to bind in components view.
function SomeComponentViewModel(params) {
   this.someProperty = params.something;
}
ko.components.register('component name', {
   viewModel: SomeComponentViewModel,
   template: ...
});
shared object instance
The viewModel object instance is shared. The instance property is passed to use the object directly.
var sharedViewModelInstance = { ... };

ko.components.register('component name', {
   viewModel: { instance: sharedViewModelInstance },
   template: ...
});
createViewModel
It calls a function which acts as a factory and can be used as view model that can return an object.
ko.components.register('component name', {  
   viewModel: {  
      createViewModel: function (params, componentInfo) {  
         ...       //function code  
         ...
      }  
   },  
   template: ....  
});
AMD module
It is a module format for defining modules where module and dependencies both are loaded asynchronously.
ko.components.register('component name', {
   viewModel: { require: 'some/module/name' },
   template: ...
});

define(['knockout'], function(ko) {
   function MyViewModel() {
      // ...
   }

   return MyViewModel;
});
Following table lists the template formats that can be used to register the components.
element ID
ko.components.register('component name', {
   template: { element: 'component-template' },
   viewModel: ...
});
element instance
var elemInstance = document.getElementById('component-template');

ko.components.register('component name', {
   template: { element: elemInstance },
   viewModel: ...
});
string of markup
ko.components.register('component name', {
   template: '<input data-bind = "value: yourName" />\
      <button data-bind = "click: addEmp">Add Emp </button>',
   viewModel: ...
});
DOM nodes
var emp = [
   document.getElementById('node 1'),
   document.getElementById('node 2'),
];

ko.components.register('component name', {
   template: emp,
   viewModel: ...
});
document fragement
ko.components.register('component name', {
   template: someDocumentFragmentInstance,
   viewModel: ...
});
AMD module
ko.components.register('component name', {
   template: { require: 'some/template' },
   viewModel: ...
});
The AMD module can register a component by itself without using viewModel/template pair.
ko.components.register('component name',{ require: 'some/module'});
There are two ways of component binding.
Full syntax − It passes the parameter and object to the component. It can pass using the following properties.

name − It adds the component name.
params − It can pass multiple parameters in object on the component.


Full syntax − It passes the parameter and object to the component. It can pass using the following properties.
name − It adds the component name.
name − It adds the component name.
params − It can pass multiple parameters in object on the component.
params − It can pass multiple parameters in object on the component.
<div data-bind='component: {
   name: "tutorials point",
   params: { mode: "detailed-list", items: productsList }
}'>
</div>
Shorthand syntax − It passes the string as a component name and it does not include parameter in it.
Shorthand syntax − It passes the string as a component name and it does not include parameter in it.
<div data-bind = 'component: "component name"'></div>

Template-only components − Components can only define template without specifing the viewModel.
Template-only components − Components can only define template without specifing the viewModel.
ko.components.register('component name', {
   template:'<input data-bind = "value: someName" />,
});
Using Component without a container element − Components can be used without using extra container element. This can be done using containerless flow control which is similar as the comment tag.
Using Component without a container element − Components can be used without using extra container element. This can be done using containerless flow control which is similar as the comment tag.
<!--ko.component: ""-->
<!--/ko-->

Custom element is a way for rendering a component. Here, you can directly write a selfdescriptive markup element name instead of defining a placeholder, where the components are binded through it.
<products-list params = "name: userName, type: userType"></products-list>
params attribute is used to pass the parameter to component viewModel. It is similar to data-bind attribute. The contents of the params attribute are interpreted like a JavaScript object literal (just like a data-bind attribute), so you can pass arbitrary values of any type. It can pass the parameter in following ways −
Communication between parent and child components − The component is not instantiated by itself so the viewmodel properties are referred from outside of the component and thus would be received by child component viewmodel. For example, you can see in the following syntax that ModelValue is the parent viewmodel, which is received by child viewModel constructor ModelProperty.
Communication between parent and child components − The component is not instantiated by itself so the viewmodel properties are referred from outside of the component and thus would be received by child component viewmodel. For example, you can see in the following syntax that ModelValue is the parent viewmodel, which is received by child viewModel constructor ModelProperty.
Passing observable expressions − It has three values in params parameter.

simpleExpression − It is a numeric value. It does not involve any observables.
simpleObservable − It is an instance that is defined on parent viewModel. The parent viewModel will automatically get the changes on observable done by child viewModel.
observableExpression − Expression reads the observable when the expression is evaluated by itself. When the observable value changes, then the result of expression can also changs over time.


Passing observable expressions − It has three values in params parameter.
simpleExpression − It is a numeric value. It does not involve any observables.
simpleExpression − It is a numeric value. It does not involve any observables.
simpleObservable − It is an instance that is defined on parent viewModel. The parent viewModel will automatically get the changes on observable done by child viewModel.
simpleObservable − It is an instance that is defined on parent viewModel. The parent viewModel will automatically get the changes on observable done by child viewModel.
observableExpression − Expression reads the observable when the expression is evaluated by itself. When the observable value changes, then the result of expression can also changs over time.
observableExpression − Expression reads the observable when the expression is evaluated by itself. When the observable value changes, then the result of expression can also changs over time.
We can pass the parameters as follows −
<some-component
   params = 'simpleExpression: 1 + 1,
      simpleObservable: myObservable,
      observableExpression: myObservable() + 1'>
</some-component>
We can pass the parameters in viewModel as follows −
<some-component
   params = 'objectValue:{a: 3, b: 2},
      dateValue: new date(),
      stringValue: "Hi",
      numericValue:123,
      boolValue: true/false,
      ModelProperty: ModelValue'>
</some-component>
The received markup is used to create a component and is selected as a part of the output. Following nodes are passed as part of the output in the component template.
template: { nodes: $componentTemplateNodes }
The names which you register in the components using ko.components.register, the same name corresponds to the custom element tag names. We can change the custom element tag names by overriding it to control using getComponentNameForNode.
ko.components.getComponentNameForNode = function(node) {
   ...
   ...   //function code
   ...
}
The custom elements can be made available immediately, if the default component loader is used and hence the component is registered using ko.components.register. If we are not using the ko.components.register and implementing the custom component loader, then the custom element can be used by defining any element name of choice. There is no need to specify configuration when you are using ko.components.register as the custom component loader does not use it anymore.
ko.components.register('custom-element', { ......... });

Example
<!DOCTYPE html>
   <head>
      <title>KnockoutJS Components</title>
      <script src = "https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
      <script src = "https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
   </head>
   
   <body>
      <!--params attribute is used to pass the parameter to component viewModel.-->
      <click params = "a: a, b: b"></click>

      <!--template is used for a component by specifying its ID -->
      <template id = "click-l">
         <div data-bind = "text: a"></div>

         <!--Use data-bind attribute to bind click:function() to ViewModel. -->
         <button data-bind = "click:function(){callback(1)}">Increase</button>
         <button data-bind = "click:function(){callback(-1)}">Decrease</button>
      </template>

      <script>
         //Here components are registered
         ko.components.register('click', {
            
            viewModel: function(params) {
               self = this;
               this.a = params.a;
               this.b = params.b;

               this.callback = function(num) {
                  self.b(parseInt(num));
                  self.a( self.a() + parseInt(num) );
               };
            },
            template: { element: 'click-l' }
         });

         //keeps an eye on variable for any modification in data
         function viewModel() {
            this.a = ko.observable(2);
            this.b = ko.observable(0);
         }

         ko.applyBindings(new viewModel() );
      </script>
      
   </body>
</html>
Output
Let's carry out the following steps to see how the above code works −
Save the above code in component_register.htm file.
Save the above code in component_register.htm file.
Open this HTML file in a browser.
Open this HTML file in a browser.
Component loaders are used to pass the template/viewModel pair asynchronously for the given component name.
The default component loader depends on the explicitly registered configuration. Each component is registered before using the component.
ko.components.defaultLoader
The default component loader can read and write using the following functions.
ko.components.register(name, configuration)
Component is registered.
ko.components.isRegistered(name)
If the particular component name is already registered, then it returns as true else false.
ko.components.unregister(name)
The component name is removed from the registry.
ko.components.get(name, callback)
This function goes turn by turn to each registered loader to find who has passed the viewModel/template definition for component name as first. Then it returns viewModel/template declaration by invoking callback. If the registered loader could not find anything about the component, then it invokes callback(null).
ko.components.clearCachedDefinition(name)
This function can be called when we want to clear the given component cache entry. If the component is needed next time, again the loaders will be consulted.
The custom component loader can be implemented in the following ways −
getConfig(name, callback) − Depending on the names, we can pass configurations programatically. We can call callback(componentConfig) to pass the configurations, where the object componentConfig can be used by the loadComponent or any other loader.
getConfig(name, callback) − Depending on the names, we can pass configurations programatically. We can call callback(componentConfig) to pass the configurations, where the object componentConfig can be used by the loadComponent or any other loader.
loadComponent(name, componentConfig, callback) − This function resolves the viewModel and the template portion of config depending upon the way it is configured. We can call callback(result) to pass the viewmodel/template pair, where the object result is defined by the following properties.

template − Required. Return array of DOM nodes.
createViewModel(params, componentInfo) − Optional. Returns the viewModel Object depending on how the viewModel property was configured.


loadComponent(name, componentConfig, callback) − This function resolves the viewModel and the template portion of config depending upon the way it is configured. We can call callback(result) to pass the viewmodel/template pair, where the object result is defined by the following properties.
template − Required. Return array of DOM nodes.
template − Required. Return array of DOM nodes.
createViewModel(params, componentInfo) − Optional. Returns the viewModel Object depending on how the viewModel property was configured.
createViewModel(params, componentInfo) − Optional. Returns the viewModel Object depending on how the viewModel property was configured.
loadTemplate(name, templateConfig, callback) − DOM nodes is passed in a template using custom logic. The object templateConfig is a property of the template from an object componentConfig. callback(domNodeArray) is called to pass an array of DOM nodes.
loadTemplate(name, templateConfig, callback) − DOM nodes is passed in a template using custom logic. The object templateConfig is a property of the template from an object componentConfig. callback(domNodeArray) is called to pass an array of DOM nodes.
loadViewModel(name, templateConfig, callback) − viewModel factory is passed in a viewModel configuration using custom logic.
loadViewModel(name, templateConfig, callback) − viewModel factory is passed in a viewModel configuration using custom logic.

    38 Lectures 
     2 hours 

 Skillbakerystudios
 Print
 Add Notes
 Bookmark this page