Introduction
You must have tried a lot of ways to develop reusable components or widgets. But what about the components like “video”, “audio” or “select” components (tags) of HTML(5)? Did you ever investigate how these components work without exposing its style, script or local DOM structure? Web applications are being developed in various ways depending on the requirements but hardly fulfil the reusability aspect across projects or modules.
This article would help up to a certain extent to create and reuse such type of web components which can be instantiated and reused in a similar way how we are instantiating and using other HTML elements.
About Web Components
Web component is a revolution in web application development. As stated for Introducing Web Components,
“Web components are a W3C specification to build a standalone component for web applications. It helps developers leverage the development process to build reusable and reliable component. This problem leads to component-based development.”
HTML provides a lot of built-in elements like video, audio, button, select, etc. These elements have its own properties, methods, attributes and CSS properties. It also allows to override its styles, but they are limited. Web components are something which allows us to develop our own custom elements which are similar to above elements or by extending above elements.
Each component has its own life cycle and encapsulated style, script and local DOM which allows interoperability of the components (HTML elements). These components can not only be reused across a single web application but can also be reused in multiple applications.
The Web component model is made up of four different specifications:
- HTML Templates – This contain markups that are consistent across web pages with the ability to inject dynamic content using JavaScript.
- Shadow DOM – This is designed to encapsulate DOM and CSS by hiding all child elements behind a shadow root. It defines functional boundaries between the DOM tree and the subtrees hide behind the shadow root. The following screenshot depicts the DOM structure of “video” tag.
- Custom Elements – This allows us to create our own custom elements with tailored DOM structure and ability to style and add behaviour logic in our own way.
- HTML Imports – This allows us to import one HTML file in another HTML file. Using HTML Imports we can import and reuse HTML Templates for Web Components. The following is an example on how to use HTML Import to import HTML files:<link rel=”import” href=”bower_components/paper-button/paper-button.html”>
About Polymer
Polymer library, developed by Google, is a set of polyfills that help you create Web Components on all major modern browsers. It provides an easy-to-use framework for developing and instantiating custom elements in a simplistic fashion very similar to the HTML’s built-in elements like button, audio, video, etc.
Custom elements look like this:
- <google-map lat=“37.790” long=“-122.390”></google-map>
- <custom-gallery></custom-gallery>
As stated in an article, Polymer helps us to develop and render custom elements by:
- Allowing us to create Custom Elements with user-defined naming schemes. These custom elements can then be distributed across the network and used by others with HTML Imports.
- Allowing each custom element to have its own template accompanied by styles and behaviour required to use that element.
- Providing a suite of ready-made UI and non-UI elements to use and extend in your project.
Installing Polymer
The recommended way to install Polymer is through Bower. So, prerequisites for installing Polymer through Bower are:
Bower is a package manager that manages dependencies for your project. If you are not familiar with Node.js and Bower, then it is recommended to read the instructions provided in respective URLs mentioned above to learn how to install and get started with it. It is not necessary to learn everything about Node.js and Bower but knowledge about installation and getting started with would be enough to install and work with PolymerJS.
Installing with Bower
Run this command from your project root folder using terminal:
bower init
This command creates bower.json file in the root folder of your project. The easiest way to create bower.json file is to press “enter” continuously for all the prompts after above command.
- bower.json looks like:
- {
- “name”: “test-project”,
- “version”: “0.0.0”,
- “license”: “MIT”,
- “ignore”: [“**/.*”, “node_modules”, “bower_components”, “test”, “tests”]
- }
Zip package can be installed from polymerwebsite.
The next step is to install Polymer
bower install -–save Polymer/polymer#^1.2.0
By running above command in terminal, Bower adds a bower_components/ folder in the root of your project and fills it with Polymer and its dependencies and updates bower.json by adding:
- “dependencies”: {
- “polymer”: “Polymer/polymer#^1.2.0”
- }
Using Polymer’s Custom Elements
The polymer also comes with a rich, predefined set of elements that you can begin taking advantage of immediately. Using polymer’s custom elements in your document typically involves the four easy steps. The following is an example of how to download and use paper-button (one of Polymer’s custom element) in your application:
Step 1: Download the paper-button Custom Element package via Bower.
By running the following Bower Command in the terminal, it will download all required files and folders to your project and add dependencies in the bower.json file as well.
bower install -–save PolymerElements/paper-button
After running above command, dependencies section of bower.json looks like the following:
- “dependencies”: {
- “paper-button”: “PolymerElements/paper-button#~1.0.8”,
- “polymer”: “Polymer/polymer#^1.2.0”
- }
Step 2: Import Polymer’s “webcomponents.js” and “polymer.html”.
Add “webcomponents.js” and “polymer.html” (available in bower_components folder) to the<head> of the index.html. Then you will be ready to use predefined custom elements in your documents.
- “bower_components/webcomponentsjs/webcomponents.js”>
- <link rel=“import” href=“bower_components/polymer/polymer.html”>
Step 3: Import the corresponding .html file in your document.
In this case, corresponding .html file refers to paper-button.html that is generally located in bower_components folder (i.e. bower_components/paper-button/paper-button.html).
- <link rel=“import” href=“bower_components/paper-button/paper-button.html”>
Step 4: Use the custom element markup anywhere in your document.
Like any other HTML element add the markup of the custom element. Generally markup name is same as the .html file name. In this case:
<paper-button></paper-button>
A huge list of the predefined set of custom elements of Polymer is available at the Polymer official website (link mentioned in the reference section). It provides detailed documentation (in Docs section) with Demo. Bower command for each element is also available in “Bower Command” section in the left panel.
Developing a New Custom Element using Polymer
Polymer library helps us to develop our own custom elements from scratch which can be assembled to develop new custom element, extended or reused across projects. Similar to HTML’s built-in elements, Polymer elements:
- Can be instantiated using the constructor of the custom element or document.createElement or adding markup in the document.
- Can be styled with default styles of external CSS.
- Can have custom behaviour logics can be defined using JavaScript.
- Support custom events handling on changing the attributes of the markup or any update in the values of the properties.
- Support data-binding
Register a custom element
A custom element can be registered by using Polymer function of Polymer library and passing prototype as the parameter to it.
There are few specifications to define a custom element:
- It is necessary that the custom element has a property in the prototype
- There should be an id attribute in the <dom-module> tag.
- And the value of id is and the name of the custom element file must have the same value to work the custom element properly.
- And this value must contain a dash (-). In this case, it is hello-world.
For example:
<dom-module id=”hello-world”>
<template>
<style>
/* CSS classes */
</style>
<!– Local DOM structure starts here –>
{{proName}}
<!– Local DOM structure ends here –>
</template>
<!– JavaScript goes here –>
var MyElement = Polymer(
{
is: “hello-world”,
properties:
{
propName:
{
type: String,
value: “Hello World!”
}
}
})
</dom-module>
The Polymer function registers the element with the browser and returns a Constructor which can be used to create new instances of the custom elements dynamically. For example:
- var el = new MyElement();
- document.body.appendChild(el);
LifeCycle callbacks
A good understanding of the Web components life cycle will enable you to build better applications and optimise the code. For example, if you need to ensure that some code runs before the DOM attached to the document, you need to know where to place the code for that event.
So when we instantiate or remove any Web component, the following functions are called during the lifecycle:
- Created
- Ready
- AttributeChanged
- actoryImpl
- attached
- detached
The sequence of the callbacks as it is listed above.
facotyImpl method will only be invoked if the element is instantiated using Constructor (see below for instantiation options).
attributeChangedmethod will be invoked whenever any attribute is changed. It gets called after ready if there is any default properties set using “properties” object or “hostAttributes” object of Polymer prototype. It also gets called if any attribute gets changed dynamically.
Instantiation of Custom Element
Instances of Custom element can be done in multiple ways:
- Using document.createElement
- var el = document.createElement(‘hello-world’);
- document.body.appendChild(el1);
- Using tags in HTML,
- <hello-world></hello-world>
- Using append of jQuery,
- $(“body”).append(“<hello-world></hello-world>”);
- Using Constructor,
- var el = new MyElement();
- document.body.appendChild(el);
Properties Declaration
Properties for the custom elements should be declared in the properties object of the prototype as shown below:
- var MyElement = Polymer(
- {
- is: “hello-world”,
- /* public properties should be defined here */
- properties:
- {
- firstName: String,
- lastName: String,
- age: Number,
- userName: “abcd”,
- details:
- {
- propName1:
- {
- type: String,
- value: “Hello”
- },
- propName2:
- {
- type: String,
- value: “World”
- }
- }
- }
- })
The properties object supports some keys for each property. Few of the keys are:
- Type: type of the property i.e. String, Number, Boolean, Date, Array or Object etc.
- Value: Default value can be set here
- Notify: Type: boolean. If `true`, the property is available for two-way data binding. In addition, an event, propertyName-changed is fired whenever the property changes.
- Observer: Value is provided in the form of String and interpreted as methods which fire on change of the value of the property.
How to change value of properties from outside the component:
Value of properties can be changed by using query selector and .propertyName. For example:
- $(“#myElement”).propertyName = “xyz”;
Data-binding
Data-binding in Polymer is a process of automatic data synchronisation between model and view. For this synchronisation, Polymer provides an ability to bind properties to local DOM of the custom elements.
A binding is created with a binding annotation (i.e. {{ }} or [[ ]]) in the host elements local DOM template. Here is an example of data-binding using curly braces:
<dom-module id=”hello-world”>
<template>
<style>
</style>
Hello {{firstName}}{{lastName}}!
</template>
var MyElement = Polymer(
{
is: “hello-world”,
properties:
{
firstName: String,
lastName: String
}
})
</dom-module>
<hello-world first-name=”Sumant” last-name=”Mishra”></hello-world>