<x-flickr> - custom Polymer element
Older Article
This article was published 12 years ago. Some information may be outdated or no longer applicable.
Let me say this upfront: Polymer is brilliant. But what is it exactly?
Polymer is a new type of library for the web, built on top of Web Components, and designed to leverage the evolving web platform on modern browsers.
In practical terms, it’s a powerful library for building your own reusable widgets for the web. Web Components bundle together several standards: Shadow DOM, templates, and custom elements.
There are loads of great resources covering these standards. If you’re interested, I’d recommend reading through the material on html5rocks.com.
For this article, I’ll focus on two things: the Shadow DOM and Custom Elements.
You’ve probably seen the Shadow DOM in action without realising it. So what is it? The Shadow DOM is an extension of an existing DOM element. A typical example: a video player in HTML. The play, pause, and stop buttons, along with the volume slider, are all Shadow DOM elements that belong to the root video player element. You can inspect them in Chrome DevTools, but first you need to enable Shadow DOM inspection. Open DevTools Settings (click the cog), find “Show Shadow DOM” under General, and tick the checkbox.
This example from W3Schools is worth trying yourself. Inspect the audio player in Chrome DevTools and you’ll see the <audio controls> element contains a #document-fragment.
Every button, slider, and control in the audio player comes from the Shadow DOM.
Why does this matter? The content is separated from the presentation. It’s encapsulated. You can project content into predefined slots and change the projection in one centralised place instead of hunting through multiple files. Want to add another control to the audio player? Modify it once, and every <audio> tag picks up the change automatically. In technical terms: the Shadow Host (the main element) contains the Shadow Root, which is the root of the DOM subtree holding the Shadow DOM nodes. This Shadow DOM Visualiser should help you see the Host/Root relationship clearly.
The second piece is the Custom Element. HTML5Rocks makes a good point: look at GMail’s source code. Even though it’s a modern web application, the markup is just divs stacked on divs stacked on divs. Custom Elements were created to give meaning to elements, make web applications more expressive, and keep them maintainable. They let you create your own HTML/DOM elements and bundle presentation and functionality into a single tag.
That’s enough background. One more thing worth showing: Polymer builds on Shadow DOM and Custom Elements, giving you a library to work with the best of both. Here’s a diagram from the Polymer Dev Team:
The idea behind the library is to provide polyfills (the red bricks in the diagram) that’ll eventually be removed as browsers catch up with native support.
You’re probably already wondering: what’s the difference between an AngularJS directive and a Polymer element? Someone at Google has already answered that.
Right, let’s build something.
The Custom Polymer element I’ve created was inspired by Addy Osmani’s x-instagram.
To see this demo in action, register for a Flickr API key. Grab your key and keep it handy.
Creating a custom element takes two steps. First, create the element definition in a single .html file. Then import it into your main file (for this article, that’ll be index.html).
Here’s the content of index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Custom flickr element using Polymer</title>
<script src="components/platform/platform.js"></script>
<link rel="import" href="src/x-flickr.html" />
</head>
<body></body>
</html>
Now let’s create the Custom Element itself, x-flickr.html. First, import the right modules. Since we’re making a REST API call, we need Polymer-JSONP:
<link rel="import" href="../components/polymer-jsonp/polymer-jsonp.html" />
<polymer-element
name="x-flickr"
attributes="apikey tag amount"
></polymer-element>
Here we’re defining the attributes our Custom Element can accept.
After this, we set up a template block for styling the Custom Element. I’ll come back to that in a moment.
At this point the element exists but doesn’t do anything. We need to call the Flickr API and pull data. Add this element:
<polymer-jsonp
id="ajax"
auto
url="http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key={{apikey}}&tags={{tag}}&per_page={{amount}}&page=1&format=json&jsoncallback="
></polymer-jsonp>
(Note the bindings. We’ll wire those up shortly.)
Now we script the Custom Element and tell it what to do with the data. Drop this inside a <script> tag:
Polymer('x-flickr', {
amount: 10,
photos: [],
apikey: '[your-API-key]',
ready: function () {
this.$.photos.model = this.photos;
this.$.ajax.addEventListener(
'polymer-response',
function (e) {
this.photos = { photos: e.detail.response.photos.photo };
this.$.photos.model = { photos: e.detail.response.photos.photo };
this.fire('x-flickr-load', {
response: e.detail.response.photos.photo,
});
}.bind(this)
);
},
});
(Tip: drop some console.log() statements into the event listener to see what the AJAX call returns.)
Here we create a photo model on a template and bind it back to the element. Inside the <template> tag, we can use the photos object as a variable:
<div class="container">
<p>Photos of <strong>{{tag}}</strong> -- showing {{amount}} results</p>
<template id="photos" repeat="{{photo in photos}}">
<div class="thumbnail">
<img
src="http://farm{{photo.farm}}.staticflickr.com/{{photo.server}}/{{photo.id}}_{{photo.secret}}.jpg"
class="img-thumbnail"
/>
</div>
</template>
</div>
That’s it. You can now use the Custom Element by adding <x-flickr> to your HTML page (with the necessary Polymer libraries loaded). You’ve got these options:
- apikey: your API key, specified as an attribute:
<x-flickr apikey="yourkey"></x-flickr> - tag: the tag to search for:
<x-flickr tag="rome"></x-flickr> - amount: number of photos to return:
<x-flickr amount=15></x-flickr>
The source code is on GitHub along with the installation instructions.
Here are a few screenshots of the Custom Element in action:
<x-flickr tag="rome" amount="4"></x-flickr>
Happy Polymering!