What problem does Polymer solve?
My website has a list of projects defined roughly as:
- Index.html
<body>
<div class="projects">
<div class="project">
<span>Project Name</span>
<video>Project Video</video>
</div>
<div class="project">
<span>2nd Project Name</span>
...
</div>
</body>
The simple way to solve this is by manually writing this template over and over for each project.
This isn't scalable however and a pain to update, so I want to encapsulate the HTML into a web-component. This would would result in an index page that looks something like this:
- Index.html
<head>
<link rel="import" href="Project.html">
</head>
<body>
<div class="projects">
<project text="Example" video="example.mp4"></project>
<project text="AnotherExample" video="example2.mp4"></project>
</div>
</body>
You'll note the custom "project" tags being used along with non-standard properties being passed into them. This is a web-component, which I need to define in Project.html
Without any frameworks, a raw web-component would result in code looking something like this (shown in full mostly for effect):
- Project.html
<template>
<div>
<span></span>
<video></video>
</div>
</template>
<script>
function(window, document, undefined) {
var template = document.querySelector('template').content;
var projectProto = Object.create(HTMLElement.prototype);
projectProto.createdCallback = function() {
var clone = document.importNode(template, true);
var shadowRoot = this.createShadowRoot();
shadowRoot.appendChild(clone);
this.spanNode = shadowRoot.querySelector("span");
this.videoNode = shadowRoot.querySelector("video");
};
projectProto.attributeChangedCallback = function(attr, oldVal, newVal) {
if (attr == "text")
this.spanNode.textContent = newVal;
else if (attr == "video")
this.videoNode.textContent = newVal;
};
window.project = document.registerElement('project', {
prototype: projectProto
});
})(window, document);
</script>
This defines the web component in VanillaJS[1], along with two data-bindings to the internal tags that need to be filled in.
Binding values directly to values however is again an unscalable solution. A number of frameworks are emerging to try solve this problem by offering data-binding for the template.
The following is the same as above but now using Google's Polymer 1.0 framework.
- Project.html
<link rel="import" href="/bower_components/polymer/polymer.html">
<polymer-element name="project">
<template>
<style>
:host {
padding: 10px;
border: 1px solid red;
}
</style>
<div>
<span>{{text}}</span>
<video>{{video}}</video>
</div>
</template>
<script>
Polymer('project', {
text: "Default",
video: "default.mp4",
});
</script>
</polymer-element>
This is obviously much cleaner[1:1] than the pure web-components example because of the in-built data-binding.
I've also shown in the above how styling can be applied to a web-component. With the above structure, I can now update the project's style individually by updating this file rather than Index.html or a separate style-sheet.