A few weeks ago I wrote a post on Web Components, specifically the technologies that make them up. In this post, I’ll focus on Polymer and I recommend you read my previous post first if you aren't familiar with some of the concepts Web Components tries to introduce. This will help give you a sense of what Polymer can provide over standard Web Components. Now, back to Polymer, which I was recently able to get my hands dirty with when I was asked to develop the user interface (UI) for a Task Management System we were developing for NaviNet’s 2015 Customer Forum. This event is a great opportunity for our engineering team to show customers and prospects where we want to take NaviNet Open. It was also a great chance for me to test the water with the latest and greatest technologies like Polymer.
Let's get started
Polymer is a library that builds on top of Web Components. It provides an easy way to create custom elements and provides some data binding as well. What is great about Polymer is there are already lots of custom elements already developed for you to consume. This not only it saves time but it’s also a terrific resource for seeing how to develop custom elements.
Before we dive in too deep, it’s important to note that Polymer recommends putting new elements into its own Git repository. Once in the Git repository, we can then use Bower to consume the element elsewhere. Although this is a good recommendation, it is also easy to put multiple elements together in the same repository if it makes logical sense. For an example of this, see https://github.com/PolymerElements/iron-overlay-behavior. When you create a repository, give it a sensible name. Ideally you want to it have the same name as the element you are creating. This will make things much easier when you come to use [Polyserve].
Polymer provides some great tools for easily creating documentation for your element. The iron-page-component will create documentation for your element while Polyserve will host your element and allow you to view its documentation. One tool, I suggest you take a look at is the basic structure of an elements Git repository. Do you remember I said Polymer has a bunch of great pre-built elements? Well, Polymer has a seed-element which is a very basic element with all the framework in place for you to get started developing your own element. Here are a few more key points that I found useful during my exploration of Polymer:
- If your Git repository name doesn't match your elements name, the `Note` beginning, available here, is particularly useful. To summarize, use the `src` attribute to give it the name of the HTML file that contains your element i.e. `src="your-element.html"`.
- Using comments in your element HTML file can bring your documentation to life. Take a look at the comments starting with `@` here, these allow certain properties to be defined for the elements documentation.
- `@demo` is particularly useful when you have multiple elements that use different demo pages. You can also use comments to add more detail to properties and functions as well as a brief explanation on how to use your element (you can use markdown when adding more details about your element).
- Hydrolysis is the name of the component that analyzes your element to create the documentation from. Beginning a property or function name with an underscore (`_`) lets the hydrolysis process know that it should appear in the private API section when creating the documentation.
Creating our Element
Now that you've got an understanding of what a Polymer element repository can look like let's take a look at how we can create our element.
The first section of any Polymer element is all the HTML imports of elements that are used within this element. There should always be a reference to `polymer.html` as this is what loads the Polymer library.
Side note, if you are using Polyserve, which you should be, then you should treat all file paths as if your element was deployed alongside the other elements it needs in a `bower_components` folder. Your path should never contain a reference to `bower_components`.
We then declare a `dom-module` element with an `id` attribute set to the name of our new element. Inside the `dom-module` you have a `template` tag and a `script` tag. Inside the template tag is where you place the HTML for your new element, this HTML will be loaded into the Shadow DOM. The `script` tag contains all the details about our new element that Polymer needs to know about.
This is the very minimum we can tell Polymer, the `is` reference equals what our element is called (some of you may remember the `is` property from extending HTML elements from my Web Components post. The `id` on the `dom-module` must match the `is` property we define in our element.
Time For Some Properties
We can specify properties on a Polymer element by populating the `properties` property. This is an object whose property names are the names of the properties we want to define. Property values define the type of property. In the code above, I have declared a `tasks` property of type `Array`, this tells Polymer's binding engine to expect an array. The `notify` also tells the binding engine that any changes made to `task` should notify any parent of the changes. For more details on how to configure properties see Polymer’s Declared Properties.
Get Me the Data
Now for loading in our tasks. For this example, assume tasks are loaded from a file called `tasks.json` and use an existing element called `iron-ajax` to handle the AJAX side of things. Before the `iron-ajax` can be consumed, it must be added to the `dependencies` property of the `bower.json`.
You can see an HTML import was added to the top of the file for `iron-ajax`, the `iron-ajax` element was added to my template, and a `url` property with a defined a default value. The `url` property of my element is then bound to the value of the `url` property of `iron-ajax` and the `` means that it is using two way binding. Any changes made to `url` in my element means that the `url` property of `iron-ajax` is also notified. For more details on data binding syntax check out Property Binding. I have also specified the `auto` attribute which means an AJAX request will be made if there is any change to the `url` property.
Note: Remember the `notify` property from earlier? Well if `iron-ajax`'s `url` property has `notify:true` then any changes made by `iron-ajax` will notify my `url` property. This is due to the combination of `` and `notify:true`.
Show Me the Data
`task.json` contains the following JSON:
So now I’ll update the template of my element to display some information about each task.
The `dom-repeat` element, which is an extension of the `template` element, was used here. The `dom-repeat` allows us to loop over an array of items and render out the same template for each item. I have bound the `items` property to the `tasks` array which means I can access each task in the template by referencing the `item` property inside my template. There are many ways to configure the `dom-repeat` element. These can be found [here].
The code above is a very crude example of loading data into a list, so what happens if that data is shared across many components on the same page? Consider if our tasks had a read/unread flag and we want to give the user a nice notification of unread tasks. This count would need to update as the user reads the tasks in our list.
Sharing Data via Parent
One solution is to share the data via a parent node like this example below:
Here the `task-manager` element loads the tasks and passes it to both the `task-notification` and the `task-list` which means both share the same source. Yet, what if we don't want the `task-notification` to be right beside the `task-list` in the DOM? This is quite likely to happen so we would have to load tasks at a common parent somewhere up the DOM tree, which isn't intuitive or very maintainable.
Events to the Rescue, Well Sort of
Sharing a common parent may work in some situations but this is not always going to be possible. Elements like `iron-signal` might be able to help send events to elements letting them know to perform a specific action, like refreshing its data from the serve. This not only means each element will make the exact same call multiple times but that the logic for updating tasks from the server is spread across multiple elements.
What We Really Want
Ideally we want to have the data interaction abstracted into another web component that can be reused across multiple elements. This web component would be responsible for updating the server and notifying any consuming elements of changes through the built-in Polymer binding engine. This results in only one place that is responsible for interacting with the server and means we can improve performance by preventing the same AJAX request multiple times.
It's Only the UI
At the end of the day, Polymer is a UI framework so there isn't too much concern with how it interacts with the server. Nevertheless, it would be good to have at least some examples of how to do this, especially when most of Polymer’s competition does provide at least a pattern for you to follow (React and Flux, Angular and providers). It was great getting to use Polymer as it gave me a good idea of where web development is heading. It also give me the chance to see how it would handle real world situations such as populating controls with data, managing styles across multiple components and even interacting with existing controls. The prototype was extremely well received at NaviNet’s 2015 Customer Forum and think it was an excellent showcase of how we are trying to use the latest technologies to make a great product for our Customers.
Interested in more posts like this?