Tag Archives: web components

Polymer for reusable web components

Wait, what? No MEAN Web Development #4? If you’ve been following my blog you’ll know I’m in the middle of a series on MEAN Web Development. Don’t worry, I’ll get back on that!

The thing is I went to an event by CoolBlue, a Dutch webshop, last week and they had a talk on their own CDN and on Polymer 0.5. While the CoolBlue CDN is quite interesting it isn’t a very good topic to blog about. Polymer looked pretty cool too though, so I wanted to blog about that while it’s still sort of fresh in my memory. Of course I won’t be writing down exactly what was told at the CoolBlue presentation. Instead I’m going to hook in on it. You probably weren’t there so let me give you a quick recap.

“Polymer 0.5, the version CoolBlue used, is great if you’re using Chrome. Polymer 0.8 (which is still in alpha) will make lots of breaking changes to the API, but it contains the proposed API for version 1.0 and fixes some shortcomings, like performance, from 0.5.”

So if anything Polymer isn’t quite production ready. I’ve never been much of an early adopter, but today that’s going to change. In this blog I’ll be discussing Polymer 0.9 (the plan was 0.8, but then 0.9 came out while I was writing)!

You can find the source code of the examples on my GitHub account in the polymer-blog repository. You’ll need to run them from a web server (I’ll explain how to do that in this post).

Also be sure to follow me on Twitter @sanderrossel for news and articles on (web) development.

Web components

But what exactly is Polymer? Polymer is a library for creating web components developed by Google. But what is a web component? Actually there’s an entire website dedicated to teaching you about web components, WebComponents.org. Let me give you a quick summary.
Web components allow you to create custom HTML elements that contain other HTML, CSS and JavaScript. That way you can, theoretically, build websites by composing HTML, rather than nest HTML, call some JavaScript, add some CSS, throw it in the mixer, and get a mess.
So by encapsulating HTML, CSS and JavaScript we can create custom HTML that we can (re)use to compose new components or pages.

An important part of web components is the Shadow DOM (sounds like something from a video game, right?). Anyway, the shadow DOM is like ‘invisible’ HTML in your HTML document, a DOM that exists next to your DOM. Think of it as a sub-DOM, but that you can’t see. So far only Chrome and Opera support the shadow DOM.

For that reason web components are currently mostly implemented using polyfills, a downloadable piece of code that fakes native support by adding modern HTML and CSS functionality to older browsers as if they were part of the standard API.

As you can see web components still has a long way to go before it’ll be supported natively by browsers and reach maturity, but luckily nothing is stopping us from already taking a look at it today. And if nothing of that rang any bells, don’t worry, it’ll become clear once we look at some examples!

Bower

First things first. We need to get Polymer up and running in our project. We have a couple of ways to do this. First, and this is the recommended way, we can install Polymer by using Bower, a package manager for the web. Alternatively we can download some zip file containing all necessary files and use that. Lastly we can pull Polymer directly from GitHub and get all the related software manually.

So let’s go with Bower. I’m assuming you’re not familiar with Bower yet (neither am I), so I’ll walk you through it step by step (assuming you’re on a Windows system). If you already know Bower, or you’d like to install Polymer using one of the other proposed methods, feel free to skip this part. I won’t be discussing the other methods.

First we need to install Bower. Even though Bower is a package manager we need a package manager to install it. More specifically we need npm (and also Node.js). You can get both on the Node.js website. Luck has it that I already discussed how to install Node.js and npm in a previous blog, MEAN web development #1: MEAN, the what and why. So I suggest you read it, or at least the part on installing Node.js and Express (that last part shows you how to use npm).

Once you’ve got Node.js and npm installed you’ll need Git. No doubt you’ve heard about Git. It’s the source control system developed by mr. Linux, Linus Torvalds, himself. You can get Git from their downloads page. When installing be sure to check the box that says “Use Git from the Windows Command Prompt”! Other than that you can leave all the defaults in place.
If you use GitHub and already have the GitHub software installed you’ll still need to install Git. GitHub is a client for the GitHub website and though it does use Git, it doesn’t use it on your local machine.

Now that we have all we need to use Bower we can actually install Bower! Open up a command prompt (yes, Bower uses the command prompt too…) and install it using npm.

npm install bower -g

Now installing Polymer is a breeze. Create a folder where you’d like to have your project, navigate to it using your command prompt and install Polymer like you would do when using npm (their syntax is very much the same).

cd "C:\MyProjects\PolymerProject\"
bower install Polymer/polymer#^0.9.0

Alternatively you could create a bower.json file, much like the Node.js package.json, and keep track of your installed packages. You can create a bower.json file manually or use the command prompt and walk through some sort of setup. In the command prompt use the following command (still in your project folder).

bower init

If you want to leave a field blank just press enter. Now you can install packages using –save and the bower.json will be updated automatically.

bower install Polymer/polymer#^0.9.0 --save

You can also omit the version and just get the latest.

After installing Polymer my bower.json looked like this.

{
    "name": "polymer-blog",
    "version": "1.0.0",
    "authors": [
        "Sander Rossel"
    ],
    "main": "index.html",
    "homepage": "https://sanderrossel.com",
    "ignore": [
        "**/.*",
        "node_modules",
        "bower_components",
        "test",
        "tests"
    ],
    "dependencies": {
        "polymer": "Polymer/polymer#~0.9.0"
    }
}

Yours may look differently dependent on what you entered in the setup.

There’s a lot more you can do with Bower, but I’ll leave it at this as this blog is actually about Polymer!

Polymer

And then we’re finally getting to Polymer! Unfortunately, because of some browser security issues, we’re going to need to run our HTML, CSS and JavaScript examples on an actual web server. No problem of course, since I already blogged about that too. So read the part “Setting up your environment” from Web development #4: PHP in the back and once you’ve installed XAMPP we’re ready to go. I’d like to make a small addition to the paragraph from that post. The default port 80 was in use on my computer (it happens). If you have the same problem either shut down the program that is using port 80 or change the port in XAMPP by going to Config -> Service and Port Settings -> Apache and change the main port.

Because we need a server I’ve put all of the examples on the same index.html page. As I already mentioned, the shadow DOM is pretty important when creating Polymer web components. By default Polymer puts the HTML tree in the main DOM though, so we’ll want to turn this off and put it in the shadow DOM instead (so the Polymer components are really self-contained). As far as I understand putting the components HTML in the shadow DOM will be default when Polymer 1.0 is officially released, for now I’m putting the following script in my header though.

<script>
    window.Polymer = window.Polymer || {};
    window.Polymer.dom = 'shadow';
</script>

On to the example. First you’ll need to install Polymer in your htdocs folder. After that create another folder called “components”. In components create a file called “hello-polymer.html”. In that file put the following HTML.

<dom-module id="hello-polymer">
    <template>
        <h2>Hello, Polymer!</h2>
        <p>This is our Hello World example.</p>
    </template>
</dom-module>
<script>
    Polymer({is: "hello-polymer"});
</script>

Now in your htdocs folder create an index.html file and put the following HTML in it.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Hello, Polymer!</title>
        <script src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
        <link rel="import" href="bower_components/polymer/polymer.html">
        <link rel="import" href="components/hello-polymer.html">
    </head>
    <body>
        <hello-polymer></hello-polymer>
    </body>
</html>

So let’s first look at the hello-polymer.html file. We start off by opening a dom-module element. Note that this is not an HTML standard! We can recognize non-standard elements by the hyphen (- symbol) in the name. For that reason, the value of our id attribute must contain at least one hyphen. The id indicates the name of  our custom element. So I’ve called it hello-polymer.
Within the dom-module element we’ll find a template element. That’s where our HTML goes. I’ve simply put an h2 header and a little paragraph in it. So that’s two elements.
Last, but not least, we need to register our custom element. We can do this by calling the Polymer function and passing it an object with the is-property and setting it to the name of our custom element.
So that’s it!

Now how can we use this custom element we just made? In the index.html you’ll need some imports. First you’ll need webcomponents-lite.min.js, second you’ll need polymer.html and last you’ll need our custom element. It’s actually these link elements that require us to use a server, as Chrome is pretty strict with linking HTML on your page.
So now we can just use our custom element! <hello-polymer></hello-polymer> is all it takes. Try it out by browsing to localhost.
Even though our body contains just one element, we can see two! Awesome!

So let’s make that a little bit more exciting. Create another file in the components folder, I’ve called it “expandable-hello-polymer.html”, and put the following code in it.

<dom-module id="expandable-hello-polymer">
    <style>
        .invisible {
            display: none;
        }
    </style>
    <template>
        <button id="btn">Click me!</button>
        <div id="body">
            <h2>Hello, Polymer!</h2>
            <p>This is our expandable Hello World example.</p>
        </div>
    </template>
</dom-module>
<script>
    Polymer({
        is: "expandable-hello-polymer",
        ready: function() {
            var btn = document.getElementById('btn');
            btn.onclick = function() {
                var body = document.getElementById('body');
                body.classList.toggle('invisible');
            };
        }
    });
</script>

In this example I’ve added a little CSS in the style element. The template contains a little more HTML too. The real trick lies in the script though. I’ve defined the ready function on the object passed to the Polymer function. Ready is executed, well, when the element is ready. The JavaScript itself is not very exciting, so I won’t get in on that.

Now what if we did the following in the example above?

<div id="body">
    <hello-polymer></hello-polymer>
</div>

That would’ve worked too! We can just use custom elements in our custom elements. We need to make sure the custom element we want to use is loaded though, we can load them in the current file (I’d recommend that) or in the file where we load our custom elements.

There’s still a little problem with the JavaScript in the above example. What if we have more elements with the id “btn”? After all, our document using the custom element doesn’t know about the button, so it might have another button with the same id. Which button will the above code fetch, the local one or the other one we don’t know about yet? This is especially tricky when not using the shadow DOM. We don’t know so let’s fix this problem. We can actually use the this object in the ready function to get access to the local DOM only. Notice that I’ve aliased this to that, since this won’t be this in the onclick event (hooray for JavaScript…).

ready: function() {
    var that = this;
    var btn = that.$.btn;
    btn.onclick = function() {
        var body = that.$.body;
        body.classList.toggle('invisible');
    };
}

So we can use this.$.elementId to get any element.  Alternatively we could use this.$$(selector) to get dynamically injected elements. $$ only returns the first found element.

And of course we can use it as follows.

<expandable-hello-polymer></expandable-hello-polymer>

In the example above you’ll notice that the text in the paragraph is now equal to the text in the hello-polymer example and we can’t change that. So what if we did want to change values inside our custom web component from the outside? The next example shows how we can use binding and how we can change attributes from outside of the Polymer component.

<dom-module id="attributes-polymer">
    <template>
        <span>This is <span>{{firstname}}</span> <span>{{lastname}}</span>'s custom element!</span>
    </template>
</dom-module>

<script>
    Polymer({
        is: "attributes-polymer",
        properties: {
            firstname: "",
            lastname: ""
        }
    });
</script>

So here we see that Polymer supports binding. If you’re familiar with AngularJS you’ll recognize the syntax. You can see we pass an object to the properties in the Polymer function. In these properties we specify the attributes we can use within this Polymer component, so firstname and lastname (attributes can’t have capitals). Then with the {{attribute}} syntax we can (two-way) bind to them. There’s an alternative syntax, [[attribute]], that indicates one-way binding. Binding is not possible with string concatenation, so I’ve put the bindings in their own span elements, that way we don’t need to concatenate.
Now in the index.html we can have the following.

<!DOCTYPE html>
<html>
    <head>
        <!-- ... -->
    </head>
    <body>
        <div>
            <label for="firstNameInput">Whose element is this?</label>
            <input id="firstNameInput" type="text" />
            <input id="lastNameInput" type="text" />
 <button id="btn">Change name</button>
        </div>
        <attributes-polymer id="elem" firstname="Sander" lastname="Rossel"></attributes-polymer>
    </body>
</html>

<script>
    var btn = document.getElementById('btn');
    btn.onclick = function() {
        var firstName = document.getElementById('firstNameInput').value;
        var lastName = document.getElementById('lastNameInput').value;
        var elem = document.getElementById('elem');
        elem.firstname = firstName;
        elem.lastname = lastName;
    };
</script>

And as you can see the values of firstname and lastname change value when you press the button.

There’s one last example I want to look into, two-way binding. This is a powerful feature that is actually pretty easy to use! So let’s put the example above in a Polymer web component and apply two-way binding to it. That means we don’t have to press a button to update the firstname and lastname values!

<dom-module id="two-way-binding-polymer">
    <template>
        <h2>Two-way binding!</h2>
        <div>
           <label for="firstNameInput">Whose element is this?</label>
           <input id="firstNameInput" type="text" value="{{firstname::input}}" />
           <input type="text" value="{{lastname::input}}" />
        </div>
        <span>This is <span>{{firstname}}</span> <span>{{lastname}}</span>'s custom element!</span>
    </template>
</dom-module>

<script>
    Polymer({
        is: "two-way-binding-polymer",
        properties: {
            firstname: {
                type: String,
                notify: true,
                value: "Sander" // optional
            },
            lastname: {
                type: String,
                notify: true,
                value: "Rossel" // optional
            }
        }
    });
</script>

There are a few things to notice here. First is the firstname and lastname properties. They’re now objects rather than just empty strings. To use two-way binding we need to set the notify flag. We also need to set readOnly to false, but since that’s a default I haven’t set it explicitly (but now you know there’s such a thing as readOnly too). Also, we must use {{attribute}} syntax for two-way binding. Last, the elements we’re binding to need to have a property-changed event. Since we’re binding to a non-custom element that doesn’t have a property-changed event we can specify the event on which to react ourselves. We do this by using the “property::event” syntax, in this case “firstname::input” and “lastname::input”.
The usage of this element is again very simple.

<two-way-binding-polymer></two-way-binding-polymer>

Conclusion

There’s obviously a lot more to Polymer and web components than what I’ve discussed in this post. At least you’ve got a little look at web components and Polymer in particular.
Now should you use this? As I’ve said before Polymer is still under development. In fact, when I wrote this article a new version came out which had some breaking changes! Next to that Polymer won’t work well (or different) on other browsers. Hopefully that’ll be fixed in different versions (of either Polymer or those other browsers).
That said, web components are awesome and really allow for some modular front-end development! Web components are also something the W3C is looking into standardizing. So I’d be looking out for Polymer, but wait until at least version 1.0 before even considering taking this into production code.

Happy coding!