+Web Components
Polymer
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
• Lead of JUG Dortmund
• Speaker, blogger & author
• Java Architect @ Canoo Engineering AG
• JavaOne Rockstar
• JSR Expert Group member www.guigarage.com@hendrikEbbers
Hendrik Ebbers
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
• UI magician
• Active speaker and writer
• Code Monkey @ Canoo Engineering AG
• http://blog.netopyr.com
@net0pyr
Michael Heinrichs
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Questions?
https://app.sli.do/event/xfb1afkm/ask
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component
Spec
Polymer A first app Real World
Applications
Content
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
frontend code today
<li class="yt-shelf-grid-item yt-uix-shelfslider-item">

<div class="yt-lockup yt-lockup-grid yt-lockup-video vve-check clearfix"
data-context-item-id="naiLVvuPCAw"

data-visibility-tracking=
"CFEQpDAYBSITCM7Or_3JucMCFY6yHAodHk0ANiiOHkCMkLzc7-qi1J0B">

<div class="yt-lockup-dismissable">

<div class="yt-lockup-thumbnail contains-addto">

<a aria-hidden="true" href="/watch?v=naiLVvuPCAw"
class=" yt-uix-sessionlink spf-link "

data-sessionlink=
"itct=CFEQpDAYBSITCM7Or_3JucMCFY6yHAodHk0ANiiOHjIKZy1oaWdoLXJjaA">

<div class="yt-thumb video-thumb">

<img src="//i.ytimg.com/vi/naiLVvuPCAw/mqdefault.jpg"
width="196" height="110"/>

</div>

Web Applications
Today
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
frontend code today
<li class=" yt-uix-shelfslider-item">

<div class="yt-lockup yt-lockup-grid yt-lockup-video vve-check clearfix" data-context-item-id="naiLVvuPCAw"

data-visibility-tracking="CFEQpDAYBSITCM7Or_3JucMCFY6yHAodHk0ANiiOHkCMkLzc7-qi1J0B">

<div class="yt-lockup-dismissable">

<div class="yt-lockup-thumbnail contains-addto">

<a aria-hidden="true" href="/watch?v=naiLVvuPCAw" class=" yt-uix-sessionlink spf-link "

data-sessionlink="itct=CFEQpDAYBSITCM7Or_3JucMCFY6yHAodHk0ANiiOHjIKZy1oaWdoLXJjaA">

<div class="yt-thumb video-thumb">

<img src="//i.ytimg.com/vi/naiLVvuPCAw/mqdefault.jpg" width="196" height="110"/>

</div>

<span class="video-time" aria-hidden="true">1:21</span>

</a>

<span class="thumb-menu dark-overflow-action-menu video-actions">

<button onclick=";return false;"

class="yt-uix-button-reverse flip addto-watch-queue-menu spf-nolink hide-until-delayloaded yt-uix-button yt-uix-button-dark-overflow-action-menu yt-uix-button-size-default yt-uix-button-has-icon no-icon-markup yt-uix-button-empty"

aria-expanded="false" aria-haspopup="true" type="button">

<span class="yt-uix-button-arrow yt-sprite"></span>

<ul class="watch-queue-thumb-menu yt-uix-button-menu yt-uix-button-menu-dark-overflow-action-menu" style="display: none;">

<li role="menuitem" class="overflow-menu-choice addto-watch-queue-menu-choice addto-watch-queue-play-next yt-uix-button-menu-item"

data-action="play-next" onclick=";return false;" data-video-ids="naiLVvuPCAw">

<span class="addto-watch-queue-menu-text">Play next</span>

</li>

<li role="menuitem" class="overflow-menu-choice addto-watch-queue-menu-choice addto-watch-queue-play-now yt-uix-button-menu-item"

data-action="play-now" onclick=";return false;" data-video-ids="naiLVvuPCAw">

<span class="addto-watch-queue-menu-text">Play now</span>

</li>

</ul>

</button>

</span>

<button class="yt-uix-button yt-uix-button-size-small yt-uix-button-default yt-uix-button-empty yt-uix-button-has-icon no-icon-markup addto-button video-actions spf-nolink hide-until-delayloaded addto-watch-later-button-sign-in yt-uix-tooltip"

type="button" onclick=";return false;" title="Watch Later" role="button"

data-video-ids="naiLVvuPCAw" data-button-menu-id="shared-addto-watch-later-login"><span

class="yt-uix-button-arrow yt-sprite"></span></button>

<button class="yt-uix-button yt-uix-button-size-small yt-uix-button-default yt-uix-button-empty yt-uix-button-has-icon no-icon-markup addto-button addto-queue-button video-actions spf-nolink hide-until-delayloaded addto-tv-queue-button yt-uix-
tooltip"

type="button" onclick=";return false;" title="TV Queue" data-video-ids="naiLVvuPCAw"

data-style="tv-queue"></button>

</div>

<div class="yt-lockup-content">

<h3 class="yt-lockup-title">

<a href="/watch?v=naiLVvuPCAw"

class=" yt-ui-ellipsis yt-ui-ellipsis-2 yt-uix-sessionlink spf-link "

data-sessionlink="itct=CFEQpDAYBSITCM7Or_3JucMCFY6yHAodHk0ANiiOHjIKZy1oaWdoLXJjaA"

title="Polizisten hören Helene Fischer&#39;s &#39;Atemlos&#39; im Polizeiauto"

aria-describedby="description-id-439757"

dir="ltr">Polizisten hören Helene Fischer&#39;s&#39;Atemlos&#39; im Polizeiauto</a>

<span class="accessible-description" id="description-id-439757"> - Duration: 1:21.</span>

</h3>

<div class="yt-lockup-byline">by <a href="/user/djgreyhair class=" yt-uix-sessionlink spf-link g-hovercard" data-name=""

data-sessionlink="itct=CFEQpDAYBSITCM7Or_3JucMCFY6yHAodHk0ANiiOHg" data-ytid="UCCBrsuWhYxpwZYSTY7kkB4A">Spass MussSein</a>

</div>

<div class="yt-lockup-meta">

<ul class="yt-lockup-meta-info">

<li>3,542,577 views</li>

<li>6 months ago</li>

</ul>

</div>

</div>

</div>

</div>

</li>
Web Applications
Today
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
frontend code tomorrow
<shelf
title="Popular on YouTube - Switzerland"
subscribers=“128,657">
<shelf-grid-item
title="iPhone 6 Plus Bend Test"
url="https://www.youtube.com/watch?v=znK652H6yQM"
thumbnail="https://i.ytimg.com/vi_webp/znK652H6yQM/mqdefault.webp"
user="Unbox Therapy"
userUrl="https://www.youtube.com/user/unboxtherapy"
views="63,732,280"
time="4 months ago">
…


Web Applications
Tomorrow
Web Component
Spec
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Spec
• Specified by W3C
• Current state of spec can be found
online: 

http://www.w3.org/standards/techs/components#w3c_all
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Spec
• Divided in 4 parts:
• HTML Templates
• Shadow DOM
• Custom Elements
• HTML Imports
<template>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
<template>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
<template>
<div class="activity-stream">

<h2>Activities</h2>



<div class="activity">

<img class="icon" src="img/hendrik.jpeg" width="40" height="40">

<div class="time">Minutes ago</div>

<div class="content"><a>Hendrik</a> did this again.</div>

</div>


…
</div>


<div class="activity">

<img class="icon" src="img/michael.jpeg" width="40" height="40">

<div class="time">Seconds ago</div>

<div class="content"><a>Michael</a> had fun coding.</div>

</div>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
<template>
<div class="activity-stream">

<h2>Activities</h2>



<div class="activity">

<img class="icon" src="img/hendrik.jpeg" width="40" height="40">

<div class="time">Minutes ago</div>

<div class="content"><a>Hendrik</a> did this again.</div>

</div>


…
</div>


<div class="activity">

<img class="icon" src="img/michael.jpeg" width="40" height="40">

<div class="time">Seconds ago</div>

<div class="content"><a>Michael</a> had fun coding.</div>

</div>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
<template>
<div class="activity">



</div>


<img class="icon" src="img/michael.jpeg" width="40" height="40">

<div class="time">Seconds ago</div>

<div class="content"><a>Michael</a> had fun coding.</div>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
<template>
<template id="activity-template">

</template>
<div class="activity">



</div>
template tag


<img class="icon" src="img/michael.jpeg" width="40" height="40">

<div class="time">Seconds ago</div>

<div class="content"><a>Michael</a> had fun coding.</div>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
<template>
<div>

<img class="icon" src="" width="40" height="40">

<div class="time"></div>

<div class="content"></div>

</div>
<template id="activity-template">

</template>
<div class="activity">



</div>
copy boilerplate
template tag


<img class="icon" src="img/michael.jpeg" width="40" height="40">

<div class="time">Seconds ago</div>

<div class="content"><a>Michael</a> had fun coding.</div>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
<template>
<div>

<img class="icon" src="" width="40" height="40">

<div class="time"></div>

<div class="content"></div>

</div>
<template id="activity-template">

</template>
<div class="activity">



</div>
copy boilerplate
template tag
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
<template>
<template id="activity-template">

<div>

<img class="icon" src="" width="40" height="40">

<div class="time"></div>

<div class="content"></div>

</div>

</template>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
<template>
<template id="activity-template">

<div>

<img class="icon" src="" width="40" height="40">

<div class="time"></div>

<div class="content"></div>

</div>

</template>
var template = document.querySelector('#activity-template');
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
<template>
<template id="activity-template">

<div>

<img class="icon" src="" width="40" height="40">

<div class="time"></div>

<div class="content"></div>

</div>

</template>
var template = document.querySelector('#activity-template');
var clone = document.importNode(template.content, true);
use content property
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
<template>
document.body.appendChild(clone);
<template id="activity-template">

<div>

<img class="icon" src="" width="40" height="40">

<div class="time"></div>

<div class="content"></div>

</div>

</template>
var template = document.querySelector('#activity-template');
var clone = document.importNode(template.content, true);
use content property
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
<template>
<template id="activity-template">

<div>

<img class="icon" ng-src="{{item.iconSrc}}" width="40" height="40">

<div class="time">{{item.time}}</div>

<div class="content">{{item.content}}</div>

</div>

</template>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
<template>
<template id="activity-template">

<div>

<img class="icon" ng-src="{{item.iconSrc}}" width="40" height="40">

<div class="time">{{item.time}}</div>

<div class="content">{{item.content}}</div>

</div>

</template>
No Data Binding
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
<template>
22+ 26+ and
Android 4.4+
7.1+ 15+
Shadow Dom
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
Web Component
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
".content"".content"
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
".content"".content"
document.querySelector(".content")
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
".content"".content"
document.querySelector(".content")
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
".content"".content"
.content {
color: blue;
}
document.querySelector(".content")
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
".content"".content"
.content {
color: blue;
}
document.querySelector(".content")
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
Host
Root
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
visible to

the user
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
visible to

the user
used during
rendering
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
document.querySelector(".content")
.content {
color: blue;
}
".content" ".content"
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
document.querySelector(".content")
.content {
color: blue;
}
".content" ".content"
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
Host
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
var root = host.createShadowRoot();
Host
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
var root = host.createShadowRoot();
Host
Root
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
var root = host.createShadowRoot();
Host
Root
root.appendChild(child1);
root.appendChild(child2);
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
var root = host.createShadowRoot();
Host
Root
root.appendChild(child1);
root.appendChild(child2);
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
Host
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Domvar root = host.createShadowRoot();
Host
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Domvar root = host.createShadowRoot();
Host
Root
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Domvar root = host.createShadowRoot();
Host
Root
var clone = document.importNode(
template.content, true);
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Domvar root = host.createShadowRoot();
Host
Root
var clone = document.importNode(
template.content, true);
Clone
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Domvar root = host.createShadowRoot();
Host
Root
var clone = document.importNode(
template.content, true);
root.appendChild(clone);
Clone
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Domvar root = host.createShadowRoot();
Host
Root
var clone = document.importNode(
template.content, true);
root.appendChild(clone);
Clone
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Shadow Dom
25+ and
Android 4.4+
15+
Custom
Elements
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elements
<div class="activity">
<a>Michael</a> had fun coding.
</div>
How do we store the icon source and time?
What is a <div> with the class “activity” anyway?
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elements
<div class="activity">
<a>Michael</a> had fun coding.
</div>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elements
<activity-card iconSrc="img/michael.jpg" time="Seconds ago">
<a>Michael</a> had fun coding.
</activity-card>
<div class="activity">
<a>Michael</a> had fun coding.
</div>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elements
var activityCardPrototype = Object.create(HTMLElement.prototype);
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elements
var activityCardPrototype = Object.create(HTMLElement.prototype);
Rough translation to Java
class ActivityCard extends HTMLElement {};
Class<ActivityCard> activityCardClass = ActivityCard.class;
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elements
var activityCardPrototype = Object.create(HTMLElement.prototype);
Rough translation to Java
class ActivityCard extends HTMLElement {};
Class<ActivityCard> activityCardClass = ActivityCard.class;
var options = {prototype: activityPrototype}
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elements
var activityCardPrototype = Object.create(HTMLElement.prototype);
Rough translation to Java
class ActivityCard extends HTMLElement {};
Class<ActivityCard> activityCardClass = ActivityCard.class;
ElementRegistrationOptions options = 

new ElementRegistrationOptions(activityCardClass);
var options = {prototype: activityPrototype}
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elements
document.registerElement("activity-card", options);
var activityCardPrototype = Object.create(HTMLElement.prototype);
Rough translation to Java
class ActivityCard extends HTMLElement {};
Class<ActivityCard> activityCardClass = ActivityCard.class;
ElementRegistrationOptions options = 

new ElementRegistrationOptions(activityCardClass);
var options = {prototype: activityPrototype}
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elements
document.registerElement("activity-card", options);
var activityCardPrototype = Object.create(HTMLElement.prototype);
document.registerElement("activity-card", options);
Rough translation to Java
class ActivityCard extends HTMLElement {};
Class<ActivityCard> activityCardClass = ActivityCard.class;
ElementRegistrationOptions options = 

new ElementRegistrationOptions(activityCardClass);
var options = {prototype: activityPrototype}
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elements
document.registerElement("activity-card", options);
var activityCardPrototype = Object.create(HTMLElement.prototype);
var options = {prototype: activityPrototype}
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elements
document.registerElement("activity-card", options);
var activityCardPrototype = Object.create(HTMLElement.prototype);
var options = {prototype: activityPrototype}
<activity-card iconSrc="img/michael.jpg" time="Seconds ago">
<a>Michael</a> had fun coding.
</activity-card>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elements
create attach detach
change
createdCallback
attachedCallback
detachedCallback
attributeChangedCallback

(attrName, oldVal, newVal)
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elements
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype);
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype);
activityPrototype.createdCallback = function() {
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype);
activityPrototype.createdCallback = function() {
var template = $("#activity-template");
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype);
activityPrototype.createdCallback = function() {
var template = $("#activity-template");
var clone = document.importNode(template.content, true);
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype);
activityPrototype.createdCallback = function() {
var template = $("#activity-template");
var clone = document.importNode(template.content, true);
var host = $(this);
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype);
activityPrototype.createdCallback = function() {
var template = $("#activity-template");
var clone = document.importNode(template.content, true);
var host = $(this);
$(".icon", clone).attr("src", host.attr("iconSrc"));
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype);
activityPrototype.createdCallback = function() {
var template = $("#activity-template");
var clone = document.importNode(template.content, true);
var host = $(this);
$(".icon", clone).attr("src", host.attr("iconSrc"));
$(".time", clone).text(host.attr("time"));
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype);
activityPrototype.createdCallback = function() {
var template = $("#activity-template");
var clone = document.importNode(template.content, true);
var host = $(this);
$(".icon", clone).attr("src", host.attr("iconSrc"));
$(".time", clone).text(host.attr("time"));
var shadow = this.createShadowRoot();
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype);
activityPrototype.createdCallback = function() {
var template = $("#activity-template");
var clone = document.importNode(template.content, true);
var host = $(this);
$(".icon", clone).attr("src", host.attr("iconSrc"));
$(".time", clone).text(host.attr("time"));
var shadow = this.createShadowRoot();
shadow.appendChild(clone);
};
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype);
activityPrototype.createdCallback = function() {
var template = $("#activity-template");
var clone = document.importNode(template.content, true);
var host = $(this);
$(".icon", clone).attr("src", host.attr("iconSrc"));
$(".time", clone).text(host.attr("time"));
var shadow = this.createShadowRoot();
shadow.appendChild(clone);
};
document.registerElement("activity-card", {prototype: activityPrototype});
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Elements
35+ and
Android 4.4.4+
26+
Html Import
<!DOCTYPE html>

<html>

<head lang="en">

<meta charset="UTF-8">

<title>Activity Stream - Standard Web Component</title>

<link href="stylesheet.css" rel="stylesheet">

<script src="bower_components/jquery/dist/jquery.min.js"></script>

</head>

<body>

<template>

<style>

* {

font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;

}

.activity {

width: 500px;

height: 40px;

padding: 10px;

background-color: #f0f8ff;

font-size: small;

margin: 10px 0;

}

.activity .icon {

float: left;

border-radius: 100%;

}



.activity .time {

float: right;

color: #b7b7b7;

font-style: italic;

}

.activity .content {

margin-left: 60px;

}

</style>



<div class="activity">

<img class="icon" src="" width="40" height="40">

<div class="time"></div>

<div class="content"><content></content></div>

</div>

</template>





<script>



var activityPrototype = Object.create(HTMLElement.prototype);



activityPrototype.createdCallback = function() {

var template = document.querySelector('template');

var clone = document.importNode(template.content, true);



var host = $(this);

$(".icon", clone).attr("src", host.attr("iconSrc"));

$(".time", clone).text(host.attr("time"));



var shadowRoot = this.createShadowRoot();

shadowRoot.appendChild(clone);

};



// Register our new element

document.registerElement('activity-card', {

prototype: activityPrototype

});

</script>



<div class="activity-stream">

<h2>Activities</h2>

<activity-card iconSrc="../img/michael.jpeg" time="Seconds ago">

<a href="profiles/michael">Michael</a> had fun writing web components.

</activity-card>

<activity-card iconSrc="../img/hendrick.jpeg" time="Minutes ago">

<a href="profiles/hendrick">Hendrick</a> blogged on <a href="http://guigarage.com">GuiGarage</a>.

</activity-card>

<activity-card iconSrc="../img/michael.jpeg" time="1 hour ago">

<a href="profiles/michael">Michael</a> needed an extra large cup of coffee.

</activity-card>

<activity-card iconSrc="../img/hendrick.jpeg" time="Yesterday">

<a href="profiles/hendrick">Hendrick</a> watched a movie.

</activity-card>

</div>

</body>

</html>
<!DOCTYPE html>

<html>

<head lang="en">

<meta charset="UTF-8">

<title>Activity Stream - Standard Web Component</title>

<link href="stylesheet.css" rel="stylesheet">

<script src="bower_components/jquery/dist/jquery.min.js"></script>

</head>

<body>

<template>

<style>

* {

font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;

}

.activity {

width: 500px;

height: 40px;

padding: 10px;

background-color: #f0f8ff;

font-size: small;

margin: 10px 0;

}

.activity .icon {

float: left;

border-radius: 100%;

}



.activity .time {

float: right;

color: #b7b7b7;

font-style: italic;

}

.activity .content {

margin-left: 60px;

}

</style>



<div class="activity">

<img class="icon" src="" width="40" height="40">

<div class="time"></div>

<div class="content"><content></content></div>

</div>

</template>





<script>



var activityPrototype = Object.create(HTMLElement.prototype);



activityPrototype.createdCallback = function() {

var template = document.querySelector('template');

var clone = document.importNode(template.content, true);



var host = $(this);

$(".icon", clone).attr("src", host.attr("iconSrc"));

$(".time", clone).text(host.attr("time"));



var shadowRoot = this.createShadowRoot();

shadowRoot.appendChild(clone);

};



// Register our new element

document.registerElement('activity-card', {

prototype: activityPrototype

});

</script>



<div class="activity-stream">

<h2>Activities</h2>

<activity-card iconSrc="../img/michael.jpeg" time="Seconds ago">

<a href="profiles/michael">Michael</a> had fun writing web components.

</activity-card>

<activity-card iconSrc="../img/hendrick.jpeg" time="Minutes ago">

<a href="profiles/hendrick">Hendrick</a> blogged on <a href="http://guigarage.com">GuiGarage</a>.

</activity-card>

<activity-card iconSrc="../img/michael.jpeg" time="1 hour ago">

<a href="profiles/michael">Michael</a> needed an extra large cup of coffee.

</activity-card>

<activity-card iconSrc="../img/hendrick.jpeg" time="Yesterday">

<a href="profiles/hendrick">Hendrick</a> watched a movie.

</activity-card>

</div>

</body>

</html>
Component Code
Application Code
Application Code
Component Code
Application Code
Application Code
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Html Import
<!DOCTYPE html>

<html>

<head lang="en">

<meta charset="UTF-8">

<title>Activity Stream - Standard Web Component</title>

<link href="stylesheet.css" rel="stylesheet">

<script src="bower_components/jquery/dist/jquery.min.js"></script>

</head>

<body>

<div class="activity-stream">

<h2>Activities</h2>

<activity-card iconSrc="../img/michael.jpeg" time="Seconds ago">

<a href="profiles/michael">Michael</a> had fun writing web components.

</activity-card>

<activity-card iconSrc="../img/hendrick.jpeg" time="Minutes ago">

<a href="profiles/hendrick">Hendrick</a> blogged on <a href="http://guigarage.com">GuiGarage</a>.

</activity-card>

<activity-card iconSrc="../img/michael.jpeg" time="1 hour ago">

<a href="profiles/michael">Michael</a> needed an extra large cup of coffee.

</activity-card>

<activity-card iconSrc="../img/hendrick.jpeg" time="Yesterday">

<a href="profiles/hendrick">Hendrick</a> watched a movie.

</activity-card>

</div>

</body>

</html>
<template>

<style>

* {

font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;

}

.activity {

width: 500px;

height: 40px;

padding: 10px;

background-color: #f0f8ff;

font-size: small;

margin: 10px 0;

}

.activity .icon {

float: left;

border-radius: 100%;

}



.activity .time {

float: right;

color: #b7b7b7;

font-style: italic;

}

.activity .content {

margin-left: 60px;

}

</style>



<div class="activity">

<img class="icon" src="" width="40" height="40">

<div class="time"></div>

<div class="content"><content></content></div>

</div>

</template>





<script>



var activityPrototype = Object.create(HTMLElement.prototype);



activityPrototype.createdCallback = function() {

var template = document.querySelector('template');

var clone = document.importNode(template.content, true);



var host = $(this);

$(".icon", clone).attr("src", host.attr("iconSrc"));

$(".time", clone).text(host.attr("time"));



var shadowRoot = this.createShadowRoot();

shadowRoot.appendChild(clone);

};



// Register our new element

document.registerElement('activity-card', {

prototype: activityPrototype

});

</script>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Html Import
<!DOCTYPE html>

<html>

<head lang="en">

<meta charset="UTF-8">

<title>Activity Stream - Standard Web Component</title>

<link href="stylesheet.css" rel="stylesheet">

<script src="bower_components/jquery/dist/jquery.min.js"></script>

</head>

<body>

<div class="activity-stream">

<h2>Activities</h2>

<activity-card iconSrc="../img/michael.jpeg" time="Seconds ago">

<a href="profiles/michael">Michael</a> had fun writing web components.

</activity-card>

<activity-card iconSrc="../img/hendrick.jpeg" time="Minutes ago">

<a href="profiles/hendrick">Hendrick</a> blogged on <a href="http://guigarage.com">GuiGarage</a>.

</activity-card>

<activity-card iconSrc="../img/michael.jpeg" time="1 hour ago">

<a href="profiles/michael">Michael</a> needed an extra large cup of coffee.

</activity-card>

<activity-card iconSrc="../img/hendrick.jpeg" time="Yesterday">

<a href="profiles/hendrick">Hendrick</a> watched a movie.

</activity-card>

</div>

</body>

</html>
<template>

<style>

* {

font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;

}

.activity {

width: 500px;

height: 40px;

padding: 10px;

background-color: #f0f8ff;

font-size: small;

margin: 10px 0;

}

.activity .icon {

float: left;

border-radius: 100%;

}



.activity .time {

float: right;

color: #b7b7b7;

font-style: italic;

}

.activity .content {

margin-left: 60px;

}

</style>



<div class="activity">

<img class="icon" src="" width="40" height="40">

<div class="time"></div>

<div class="content"><content></content></div>

</div>

</template>





<script>



var activityPrototype = Object.create(HTMLElement.prototype);



activityPrototype.createdCallback = function() {

var template = document.querySelector('template');

var clone = document.importNode(template.content, true);



var host = $(this);

$(".icon", clone).attr("src", host.attr("iconSrc"));

$(".time", clone).text(host.attr("time"));



var shadowRoot = this.createShadowRoot();

shadowRoot.appendChild(clone);

};



// Register our new element

document.registerElement('activity-card', {

prototype: activityPrototype

});

</script>
activity-card.html
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Html Import
<!DOCTYPE html>

<html>

<head lang="en">

<meta charset="UTF-8">

<title>Activity Stream - Standard Web Component</title>

<link href="stylesheet.css" rel="stylesheet">

<script src="bower_components/jquery/dist/jquery.min.js"></script>

</head>

<body>

<div class="activity-stream">

<h2>Activities</h2>

<activity-card iconSrc="../img/michael.jpeg" time="Seconds ago">

<a href="profiles/michael">Michael</a> had fun writing web components.

</activity-card>

<activity-card iconSrc="../img/hendrick.jpeg" time="Minutes ago">

<a href="profiles/hendrick">Hendrick</a> blogged on <a href="http://guigarage.com">GuiGarage</a>.

</activity-card>

<activity-card iconSrc="../img/michael.jpeg" time="1 hour ago">

<a href="profiles/michael">Michael</a> needed an extra large cup of coffee.

</activity-card>

<activity-card iconSrc="../img/hendrick.jpeg" time="Yesterday">

<a href="profiles/hendrick">Hendrick</a> watched a movie.

</activity-card>

</div>

</body>

</html>
<template>

<style>

* {

font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;

}

.activity {

width: 500px;

height: 40px;

padding: 10px;

background-color: #f0f8ff;

font-size: small;

margin: 10px 0;

}

.activity .icon {

float: left;

border-radius: 100%;

}



.activity .time {

float: right;

color: #b7b7b7;

font-style: italic;

}

.activity .content {

margin-left: 60px;

}

</style>



<div class="activity">

<img class="icon" src="" width="40" height="40">

<div class="time"></div>

<div class="content"><content></content></div>

</div>

</template>





<script>



var activityPrototype = Object.create(HTMLElement.prototype);



activityPrototype.createdCallback = function() {

var template = document.querySelector('template');

var clone = document.importNode(template.content, true);



var host = $(this);

$(".icon", clone).attr("src", host.attr("iconSrc"));

$(".time", clone).text(host.attr("time"));



var shadowRoot = this.createShadowRoot();

shadowRoot.appendChild(clone);

};



// Register our new element

document.registerElement('activity-card', {

prototype: activityPrototype

});

</script>
activity-card.html
<link rel="import" href="activity-card.html">
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Html Import
36+ and
Android Browser
37
26+
Use Web
Components today
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
webcomponent.js
• Today not all browsers support the new standards
• The community provides a pollyfills to enable web
components in browser that have no native support
$ bower install --save webcomponentsjs
<script src="bower_components/webcomponentsjs/webcomponents.js"></script>
install it with bower
use it in your code
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
webcomponent.js
• The polyfills are the junction of X-Tag and
Polymer basic libraries
• Mozilla created X-Tag as a polyfill to provide
web components
• Google created Polymer as a polyfill to
provide web components
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
webcomponent.js
• X-Tag and Polymer depends on
webcomponents-js
• Both libraries provide additional
features that are not part of the
specification
webcomponents.org
Polymer
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Polymer
• Adds sugar on top of web components
• Easy to use
• Extendable
• Polymer is created & supported by
Google
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Polymer
• Separated in several parts:
• Polymer API
• Iron Elements
• Paper Elements
• …
www.polymer-project.org
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Polymer
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Iron Elements
• Iron Elements are low level components
• Most Paper UI components base on Iron
• Icons, layouts …
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Icons
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Icons
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Google Web Components
• Google is building a lot of components
(maps, youtube…)
<google-chart></google-chart>
<google-hangout-button></google-hangout-button>
Paper Elements
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Polymer Paper
• Complete component library based on
Material Design
Bower
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Bower
• A package manager for the web
• Search for dependencies and install
them as packages
• Created by Twitter
• Open Source
www.bower.io
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Bower
requires npm, node.js and git
$ npm install -g bower
$ bower init
$ bower install --save webcomponentsjs
in your project folder
download &
add module
add dependency to
bower file
Polymer Paper
Components
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
How to use Components
• All components are build as web components
• A single component or a set can be added by
using bower
$ bower install --save Polymer/paper-slider
<link rel="import" href="bower_components/paper-slider/paper-slider.html">
import it in HTML
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Paper Button
• The default Button
• shows ripple animation on click
<paper-button>flat button</paper-button>
<paper-button raised>raised button</paper-button>
<paper-button noink>No ripple effect</paper-button>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Paper CheckBox
• A styled CheckBox
• State can be defined as attribute
<paper-checkbox></paper-checkbox>
<paper-checkbox checked></paper-checkbox>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Paper Dialog
• A dialog
• Supports title, modality, actions, …
<paper-dialog heading="Title">
<p>Some content</p>
</paper-dialog>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Overview
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Overview
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Layout
• HeaderPanel
• Toolbar
• DrawerPanel
• Scaffold
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Toolbar
• An application toolbar
• Toolbar content will be aligned
<core-toolbar>
<paper-icon-button icon="menu"></paper-icon-button>
<div>My Application</div>
<span flex></span>
<paper-icon-button icon="event"></paper-icon-button>
</core-toolbar>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
HeaderPanel
• Wrapper around toolbar and content
• Toolbar always on top
• Content scrollable
<core-header-panel flex>
<core-toolbar>Title</core-toolbar>
<div>content</div>
</core-header-panel>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
DrawerPanel
• Adds a responsive menu
• Defines attributes to
open and close the
menu
• Normally wraps 2 core-
header-panel
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
DrawerPanel
<core-drawer-panel>
<core-header-panel drawer>
<core-toolbar></core-toolbar>
<core-menu>
<core-item label="One"></core-item>
</core-menu>
</core-header-panel>
<core-header-panel main>
<core-toolbar>
<paper-icon-button core-drawer-toggle icon="menu"></paper-icon-button>
</core-toolbar>
<div>content</div>
</core-header-panel>
</core-drawer-panel>
drawer panel
main panel
show drawer
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Scaffold
• Basic skeleton
• Best practice to
create an
application
• Contains all the
shown features
<core-scaffold>
<core-header-panel navigation flex>
<!-- nav drawer -->
</core-header-panel>
<span tool>Title</span>
<div>content</div>
</core-scaffold>
defines the drawer
defines the main
toolbar
using Paper
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Paper Demo
• Create a new folder
• Install needed modules with Bower
$ mkdir app
$ cd app
$ bower init
$ bower install --save PolymerElements/paper-elements
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Paper Demo
• Create index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>Hello World</body>
</html>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Paper Demo
• add webcomponents.js
• 
<head>
. . .
<script src=„bower_components/webcomponentsjs/webcomponents.js">
</script>
</head>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Paper Demo
• add Roboto Font
• 
<head>
<link rel="import" href=„bower_components/font-roboto/
roboto.html">
<style>
html,body {
font-family: 'RobotoDraft', sans-serif;
}
</style>
</head>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Paper Demo
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Paper Demo
• add a header panel with a toolbar
<body class="fullbleed layout vertical">

<paper-header-panel class="flex">

<paper-toolbar>Title</paper-toolbar>

</paper-header-panel>

</body>

<link rel=„import" href="bower_components/paper-styles/paper-styles.html">
<link rel=„import" href="bower_components/paper-header-panel/paper-header-panel.html">
<link rel="import" href="bower_components/paper-toolbar/paper-toolbar.html">
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Paper Demo
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Paper Demo
• Add some content to the toolbar
<link rel=„import" href="bower_components/iron-icons/iron-icons.html">
<link rel="import" href="bower_components/paper-icon-button/paper-icon-button.html">
<paper-toolbar>

<paper-icon-button icon="menu"></paper-icon-button>

<span class="flex">Title</span>

<paper-icon-button icon="add"></paper-icon-button>

<paper-icon-button icon="remove"></paper-icon-button>

</paper-toolbar>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Paper Demo
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Paper Demo
• Add paper elements as content
<link rel="import"
href=„bower_components/paper-input/paper-input.html">
<link rel="import"
href="bower_components/paper-button/paper-button.html">
<div class="layout vertical">
<paper-input label="Name"></paper-input>
<paper-input label="Description"></paper-input>
<paper-button raised>save</paper-button>
</div>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Paper Demo
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Paper Demo
• Add some padding
.content {
padding: 20px;
}
<div class="content layout vertical">
<paper-input label="Name"></paper-input>
<paper-input label="Description"></paper-input>
<paper-button raised>save</paper-button>
</div>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Paper Demo
www.guigarage.com
Custom
Components
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Components
• Polymer can be used to create custom
web components
• Defines a nice and modern API to create
components
• Adds several features on top of the spec
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
A First Example
<link rel=„import" href="bower_components/polymer/polymer.html">
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
A First Example
<link rel=„import" href="bower_components/polymer/polymer.html">
<dom-module id="dom-element">
</dom-module>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
A First Example
<link rel=„import" href="bower_components/polymer/polymer.html">
<dom-module id="dom-element">
<template>
<p>I'm a DOM element. This is my local DOM!</p>
</template>
</dom-module>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
A First Example
<link rel=„import" href="bower_components/polymer/polymer.html">
<dom-module id="dom-element">
<template>
<p>I'm a DOM element. This is my local DOM!</p>
</template>
<script>
Polymer({is: "dom-element"});
</script>
</dom-module>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
• Component name must contain a "-"
• Polymer script call must be included
• Template is not needed
• Once it is created it can be used as
custom tag
Custom Components
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Lifecycle
• Polymer defines it’s own lifecycle that is
based on the Web Component Spec
lifecycle
• Callbacks can simply be defined in
Polymer
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Difference to Spec
• created instead of createdCallback
• attached instead of attachedCallback
• detached instead of detachedCallback
• attributeChanged instead of
attributeChangedCallback
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Additional Callback
• Polymer adds an extra callback ready which is
invoked when Polymer has finished creating and
initializing the element’s local DOM.
• The created callback is always called before
ready.
• The ready callback is always called before
attached.
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Example<script>
Polymer({
is: „dom-element“,
ready: function () {
console.log('Ready!');
},
detached: function() {
console.log(this.localName + '#' + this.id + ' was detached');
},
attributeChanged: function(name, type) {
console.log('Attribute ' + name + ' was changed');
}
});
</script>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Property
• Properties can be specified for a
Polymer component
• A property can be of the following types:
• Boolean, Date, Number, String,
Array or Object
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Property
• Properties can be defined in JavaScript
Polymer({
is: 'my-component',
properties: {
user: String,
isHappy: Boolean
}
});
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Property
• Properties can be set in JavaScript







Properties can be set as HTML attribute
ready: function () {
this.set(‘user‘,’unknown‘);
}
<my-component user=‘unknown‘></my-component>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Property
• Default value can be specified
properties: {
user: {
type: String,
value: ‘unknown‘
},
isHappy: Boolean
}
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Data Binding
• binds a property to an attribute of an
element



• Use [[prop]] for one-way-binding
• Property defines if {{prop}} is one-way or
bidirectional binding
<child-element name="{{myName}}"></child-element>
Ok, let’s create
an application
Mockup
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Basic
Layout
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Application Basic Layout
• Header with fixed size

• Resizeable main area

• Footer with fixed size
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Polymer Layout
• The Polymer layout is based on flexbox
• Use Polymer layout classes to simplify
the usage of flexbox
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Flexbox
• New CSS 3 layout
• Flexbox consists of flex containers and
flex items.
box box box
container
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Flexbox
• Contents can be laid out in any flow direction (leftwards,
rightwards, downwards, or even upwards!)
• Contents can be laid out linearly along a single (main) axis
or wrapped into multiple lines along a secondary (cross)
axis
• Contents can “flex” their sizes to respond to the available
space
• …
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Flexbox
box box box
container
flex-direction: row;
box
box
box
container
flex-direction:column;
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Flexbox
box box box
container
flex: 0; flex: 0;flex: 1;
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Application Basic Layout
fix height
fix height
dynamic
height
flexbox
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Using Flex Box in Polymer
• Polymer defines several layout classes
• layout: basic class that must be set
• horizontal: layout content in a row
• vertical: layout content in a column
• flex: content will fill space
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Polymer Layout
Alpha Beta Gamma
<div class="horizontal layout">
<div>Alpha</div>
<div class="flex">Beta (flex)</div>
<div>Gamma</div>
</div>
Application
Structure
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Application Structure
• A Polymer application is based on web
components
• The components define a hierarchy
• chat-view component contains
several chat-bubble components
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Application Structure
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Application Structure
Yeah!
message-view
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
chat-bubble
Application Structure
Yeah!
message-view
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
chat-view
chat-bubble
Application Structure
Yeah!
message-view
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
app-view
chat-view
chat-bubble
Application Structure
Yeah!
message-view
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Like building futuristic Matrjoschkas with Lego
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Application Structure
• The demo will use bower to handle all
dependencies
• Real applications should use a build
script
• like Gulp or Grunt
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
index.html
• add web components polyfill script
• Import basic dependencies like Roboto-
Font and Polymer layouts
• body contains only one web
component: the application
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
imports


<script src="bower_components/webcomponentsjs/webcomponents.js"></script>



<link rel="import" href="bower_components/paper-styles/paper-styles.html">

<link rel="import" href="bower_components/font-roboto/roboto.html">

PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
imports


<script src="bower_components/webcomponentsjs/webcomponents.js"></script>



<link rel="import" href="bower_components/paper-styles/paper-styles.html">

<link rel="import" href="bower_components/font-roboto/roboto.html">

web components polyfill
font and layouts
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
component-xy.html
• Contains the definition of one web
component
• All components that are needed
internally should be imported
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Workspace
bower.json
index.html
chat-bubble.html
chat-view.html
chat-header.html
chat-footer.html
chat-app.html
Chat Bubble
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Chat Bubble
Sender
This is the chat message. The size of the
bubble should fit to this message. Next to
normal text emojis can be part of a
message: 😊
5 min ago
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Chat Bubble
Sender
This is the chat message. The size of the
bubble should fit to this message. Next to
normal text emojis can be part of a
message: 😊
5 min ago
depends on parent width
dependsontextlength
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Chat Bubble
Sender
This is the chat message. The size of the
bubble should fit to this message. Next to
normal text emojis can be part of a
message: 😊
5 min ago
dependsontext
length
fix
fix
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Chat Bubble
Sender
This is the chat message. The size of the
bubble should fit to this message. Next to
normal text emojis can be part of a
message: 😊
5 min ago
fix
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Chat Bubble
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Chat Bubble
<div id="bubble"><div>
#bubble {

background-color: #F2F2F2;

border-radius: 5px;

}
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Chat Bubble
Sender
This is the chat message. The size of the
bubble should fit to this message. Next to
normal text emojis can be part of a
message: 😊
5 min ago
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Chat Bubble
<div id="bubble"><div>
#bubble {

background-color: #F2F2F2;

border-radius: 5px;
padding: 2px 12px 2px 12px;
}
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Chat Bubble
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
CSS ::after Selector
p::after {

content: " - Remember this";

}
• The ::after selector inserts something after
the content of each selected element(s).
• Use the content property to specify the
content to insert.
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Chat Bubble
#bubble::after {

background-color: #F2F2F2;

display: block;

position: absolute;

content: "00a0";

height: 16px;

width: 20px;

bottom: 11px;

transform: rotate(29deg) skew(-35deg);

}
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Chat Bubble Web Component
<dom-module id=„chat-bubble">
<style>
#bubble { . . . }
</style>


<template>
<div id=„bubble"> . . . </div>
</template>


</dom-module>


<script>
Polymer({

is: "chat-bubble"
});
</script>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Chat Bubble Attributes
• Sender & message should be dynamic
• Can be defined as attributes of the
component
• Use Polymer properties
properties: {

text: String,

sender: String

}
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Problem
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
configure Bubble with CSS
#bubble {

. . .

}
• We can specify 2 separate CSS classes:
me and you
.me {
. . .
}
.you {
. . .
}
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
• We can dynamically change the CCS
class in JS code
• Access bubble div in Polymer

• Mutate class list
change Css class
bubbleDiv.classList.remove('me');

bubbleDiv.classList.add('you');
var bubbleDiv = this.$.bubble;
id of the div
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
• Polymer provides observers for
properties



• Observer will be called whenever
property values changes
Property Observer
me: {
type: Boolean,

observer: ‚_senderChanged'
}
_senderChanged: function (newValue, oldValue) {

this.updateStyleClass(newValue);

}
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
• The initial boolean property value
reflects if a HTML attribute is set
use boolean property
<chat-bubble me></chat-bubble>
<chat-bubble></chat-bubble>
„me“ property == true
„me“ property == false
Chat View
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Chat View
• Should contain a list of chat bubbles
• Scrollable
• based on data array (JSON)
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Polymer Iron
• List of low level components
• Define behavior
• Don’t define theme / skin
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
iron-list
• Defines a list that can be scrolled
• Can contain thousands of elements.
Only visible area is rendered
• Define a template for each cell
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
iron-list
<iron-list items="[[data]]" as="item">

<template>

<chat-bubble text=„[[item.message]]" …></chat-bubble>

</template>

</iron-list>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
provide dummy data
<iron-ajax url="data.json" last-response="{{messages}}" auto></iron-ajax>

• Polymer provides Iron Element to load
JSON data
Application
Header
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Centered Text
• The name should be centered
• Layout should not be effected by
other nodes
.centered {

top: 18px;

left: 0;

position:absolute;

width: 100%;

}
.title {

font-size: 22px;

text-align:center;

}
parent of text text
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Rounded Image
• Avatar image should be rounded
.avatar {

width: 64px;

height: 64px;

border-radius: 32px;

border-style: solid;

border-width: 1px;

border-color: lightgrey;

}
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Dynamic content
• Add some Polymer properties





• Use them inline

Properties: {

title: String,

state: String

}
<div class="centered vertical layout">

<div class="title">{{title}}</div>

<div class="subtitle">{{state}}</div>

</div>
Application
Footer
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Textbox
• <input> can be styled with CSS
• Polymer provides a behavior to add
data binding to a normal input
<input is="iron-input" value="{{message::input}}">
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Custom Button
• Call a internal web component function
when the button is clicked
<button on-click="sendMyMessage">send</button>
Polymer({

is: "input-view",

sendMyMessage: function (e) {…}

});
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Polymer events
• Web Components can fire events

• Observer can be added

• Hint: trigger a resize for iron-list when
content changes:

this.fire('message-send', {message: this.message});
<input-view on-message-send="send"></input-view>
this.$.itemsList.fire('resize');
Emoji Support
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
About Emojis
• All emojis are defined by a a unicode
character
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Emojis in HTML
• Most OS provide a font to render emojis
• As long as the browser supports
unicode and your files are encoded in
unicode you can use them
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Parse Emojis
• Cool lib with word - emoji mapping can be
found here: 

github.com/muan/emojilib
• A Polymer Emoji selector can be found here:

github.com/notwaldorf/emoji-selector
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Emojis in the chat
var converted = '';

var words = input.split(' ');

for (var i = 0; i < words.length; i++) {

var emoji = getMeAnEmoji(words[i]);

if(emoji != '') {

converted = converted + ' ' + emoji;

} else {

converted = converted + ' ' + words[i];

}

}
Adding a
server
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Dolphin Platform
• Enterprise Framework with
Presentation Model pattern
• Server centric logic
• Spring and JavaEE integration
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Dolphin Platform
• JavaFX, AngularJS & Google Polymer
client APIs









… More will come
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Dolphin Platform
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Model
• Defined in Java
• Hierarchical models are no problem
• Full observable
• Collection support
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Model
@DolphinBean
public class MyModel {
private Property<String> name;
public Property<String> nameProperty() {return name;}
}
Dolphin Platform propere can be
used on client and server
This is NOT a JFXProperty
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Controller
• Controller is defined on the server
• Will be managed by the container
(Spring, JavaEE, …)
• Full CDI support
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Controller
@DolphinController
public class MyController {
@DolphinModel
private MyModel model;
@PostConstruct
public void init() {
model.nameProperty().onChange(e -> System.out.println(„CHANGE“));
}
}
Inject the model
Use containerfeatures
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
View
• The smallest part ;)
• Use the complete UI Toolkit power
• Simply bind your view to the model
• Trigger controller actions
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
View
<dom-module id="my-view">
<template>
<paper-input label="Task name" value="{{model.name}}"></paper-input>
</template>
</dom-module>
<script>
Polymer({
is: "my-view",
behaviors: [clientContext.createBehavior('MyController')]
});
</script>
Dolphin Platform providesPolymer behavior
Server controller
Dolphin Platformmodel
Chat App
PolymerWeb Components & by
Sending a message
Client Server
PolymerWeb Components & by
Sending a message
Client Server
call DolphinAction
PolymerWeb Components & by
Sending a message
Client Server
Event
Bus
call DolphinAction
PolymerWeb Components & by
Sending a message
Client Server
Event
Bus
call DolphinAction
publish
PolymerWeb Components & by
Sending a message
Client Server
Event
Bus
call DolphinAction
publish
PolymerWeb Components & by
Sending a message
Client Server
Event
Bus
call DolphinAction
publish
notify
PolymerWeb Components & by
Sending a message
Client
Presentation
Model
Server
Event
Bus
call DolphinAction
publish
notify
PolymerWeb Components & by
Sending a message
Client
Presentation
Model
Server
Event
Bus
call DolphinAction
publish
notifyupdate
PolymerWeb Components & by
Sending a message
Client
Presentation
Model
Server
Event
Bus
call DolphinAction
publish
notifyupdate
PolymerWeb Components & by
Sending a message
Client
Presentation
Model
Server
Event
Bus
call DolphinAction
publish
notifyupdate
synced
automatically
PolymerWeb Components & by
client code diff
Additional
Topics
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Additional Topics
• Behaviors
• Animations
• Custom CSS properties
• DOM manipulation
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Additional Topics
• Polymer contains more features
• Explorer the Polymer Catalog

• Read the documentation
https://elements.polymer-project.org
https://www.polymer-project.org/1.0/docs/
Real World
Applications
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Real World
• Todo
Polymer
Starter Kit
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Polymer Starter Kit
• Fully functional mini-application
• Defines application structure
• Contains many useful configurations

(e.g. for gitignore, jshint, travis)
• Sophisticated build script
• Sidenote: all files contain copyright headers
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Polymer Starter Kit
• Minification ( js, css, images)
• Inlining of HTML Imports
• Cache Config for Offline Usage
• Local Server (with browser-sync)
• Testing
Web Component
Tester
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester
npm install -g web-component-tester
wct
Installation
Usage
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester
• Integrates Mocha, Chai, and Sinon
• Runs with Selenium
• Integration with Sauce Labs provided
• By default runs all tests in test/
• Tasks for grunt and gulp available

(though gulp integration is sub-optimal)
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester
<head>

<meta charset="utf-8">

<script src="../bower_components/webcomponentsjs/webcomponents.min.js">
</script>

<script src="/web-component-tester/browser.js"></script>

<link rel="import" href="../chat-bubble.html">

</head>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester
<head>

<meta charset="utf-8">

<script src="../bower_components/webcomponentsjs/webcomponents.min.js">
</script>

<script src="/web-component-tester/browser.js"></script>

<link rel="import" href="../chat-bubble.html">

</head>
web component polyfill
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester
<head>

<meta charset="utf-8">

<script src="../bower_components/webcomponentsjs/webcomponents.min.js">
</script>

<script src="/web-component-tester/browser.js"></script>

<link rel="import" href="../chat-bubble.html">

</head>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester
<head>

<meta charset="utf-8">

<script src="../bower_components/webcomponentsjs/webcomponents.min.js">
</script>

<script src="/web-component-tester/browser.js"></script>

<link rel="import" href="../chat-bubble.html">

</head> provided by wct
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester
<head>

<meta charset="utf-8">

<script src="../bower_components/webcomponentsjs/webcomponents.min.js">
</script>

<script src="/web-component-tester/browser.js"></script>

<link rel="import" href="../chat-bubble.html">

</head>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester
<head>

<meta charset="utf-8">

<script src="../bower_components/webcomponentsjs/webcomponents.min.js">
</script>

<script src="/web-component-tester/browser.js"></script>

<link rel="import" href="../chat-bubble.html">

</head>
component under test
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester
<body>
<test-fixture id="chatBubbleFixture">

<template>

<chat-bubble></chat-bubble>

</template>

</test-fixture>
...
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester
<body>
<test-fixture id="chatBubbleFixture">

<template>

<chat-bubble></chat-bubble>

</template>

</test-fixture>
...
provided by wct
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester
<body>
<test-fixture id="chatBubbleFixture">

<template>

<chat-bubble></chat-bubble>

</template>

</test-fixture>
...
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester
<body>
<test-fixture id="chatBubbleFixture">

<template>

<chat-bubble></chat-bubble>

</template>

</test-fixture>
...
web component under test
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester<script>

describe('<chat-bubble>', function() {

it('should show the sender', function(done) {

var chatBubble = fixture('chatBubbleFixture');

chatBubble.set('sender', 'Test Sender');

setTimeout(function () {

expect(chatBubble.$$('.sender'))
.to.have.property('textContent')

.that.contains('Test Sender');

done();

});

});

});

</script>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester<script>

describe('<chat-bubble>', function() {

it('should show the sender', function(done) {

var chatBubble = fixture('chatBubbleFixture');

chatBubble.set('sender', 'Test Sender');

setTimeout(function () {

expect(chatBubble.$$('.sender'))
.to.have.property('textContent')

.that.contains('Test Sender');

done();

});

});

});

</script>
create component
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester
<script>

describe('<chat-bubble>', function() {

it('should show the sender', function(done) {

var chatBubble = fixture('chatBubbleFixture');

chatBubble.set('sender', 'Test Sender');

setTimeout(function () {

expect(chatBubble.$$('.sender'))
.to.have.property('textContent')

.that.contains('Test Sender');

done();

});

});

});

</script>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester
<script>

describe('<chat-bubble>', function() {

it('should show the sender', function(done) {

var chatBubble = fixture('chatBubbleFixture');

chatBubble.set('sender', 'Test Sender');

setTimeout(function () {

expect(chatBubble.$$('.sender'))
.to.have.property('textContent')

.that.contains('Test Sender');

done();

});

});

});

</script>
set property
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester<script>

describe('<chat-bubble>', function() {

it('should show the sender', function(done) {

var chatBubble = fixture('chatBubbleFixture');

chatBubble.set('sender', 'Test Sender');

setTimeout(function () {

expect(chatBubble.$$('.sender'))
.to.have.property('textContent')

.that.contains('Test Sender');

done();

});

});

});

</script>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester<script>

describe('<chat-bubble>', function() {

it('should show the sender', function(done) {

var chatBubble = fixture('chatBubbleFixture');

chatBubble.set('sender', 'Test Sender');

setTimeout(function () {

expect(chatBubble.$$('.sender'))
.to.have.property('textContent')

.that.contains('Test Sender');

done();

});

});

});

</script>
needs to be
asynchronous
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester<script>

describe('<chat-bubble>', function() {

it('should show the sender', function(done) {

var chatBubble = fixture('chatBubbleFixture');

chatBubble.set('sender', 'Test Sender');

setTimeout(function () {

expect(chatBubble.$$('.sender'))
.to.have.property('textContent')

.that.contains('Test Sender');

done();

});

});

});

</script>
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester<script>

describe('<chat-bubble>', function() {

it('should show the sender', function(done) {

var chatBubble = fixture('chatBubbleFixture');

chatBubble.set('sender', 'Test Sender');

setTimeout(function () {

expect(chatBubble.$$('.sender'))
.to.have.property('textContent')

.that.contains('Test Sender');

done();

});

});

});

</script>
DOM-query
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester
module.exports = {

plugins: {

sauce: {

browsers: [

{

platform: 'Windows 8.1',

browserName: 'internet explorer',

version: '11.0'

}

]

}

}

};
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Web Component Tester
module.exports = {

plugins: {

sauce: {

browsers: [

{

platform: 'Windows 8.1',

browserName: 'internet explorer',

version: '11.0'

}

]

}

}

};
environment
configuration
Create reusable
components
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Situation
• All components are part of our project
• We can’t reuse them in other projects
• The components are not isolated
• Looks like a bad mixup
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
Wish list
• We want reusable components
• A component should be independent and
isolated
• Components can depend on each other /
include other custom components
• Use a component as a bower dependency
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
seed-element
• Blueprint for custom component
• Defines demo, test, and main section
• Web component tester and polyserve
integrated
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
polyserve
• Polymer offers a special web server to
create reusable components
• serves project files under /components/
{bower-name}/
• other component are served from ./
bower_components/
PolymerWeb Components & by
Questions: https://goo.gl/iZI3l0
polyserve
• Your component can refer to external
components like your component is in the
bower_components folder
• Simple to create a github repo for one
specific reusable component
• Polymer Paper is doing the same
Questions?

BUILDING MODERN WEB UIS WITH WEB COMPONENTS @ Devoxx

  • 1.
  • 2.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 • Lead of JUG Dortmund • Speaker, blogger & author • Java Architect @ Canoo Engineering AG • JavaOne Rockstar • JSR Expert Group member www.guigarage.com@hendrikEbbers Hendrik Ebbers
  • 3.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 • UI magician • Active speaker and writer • Code Monkey @ Canoo Engineering AG • http://blog.netopyr.com @net0pyr Michael Heinrichs
  • 4.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Questions? https://app.sli.do/event/xfb1afkm/ask
  • 5.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Spec Polymer A first app Real World Applications Content
  • 8.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 frontend code today <li class="yt-shelf-grid-item yt-uix-shelfslider-item">
 <div class="yt-lockup yt-lockup-grid yt-lockup-video vve-check clearfix" data-context-item-id="naiLVvuPCAw"
 data-visibility-tracking= "CFEQpDAYBSITCM7Or_3JucMCFY6yHAodHk0ANiiOHkCMkLzc7-qi1J0B">
 <div class="yt-lockup-dismissable">
 <div class="yt-lockup-thumbnail contains-addto">
 <a aria-hidden="true" href="/watch?v=naiLVvuPCAw" class=" yt-uix-sessionlink spf-link "
 data-sessionlink= "itct=CFEQpDAYBSITCM7Or_3JucMCFY6yHAodHk0ANiiOHjIKZy1oaWdoLXJjaA">
 <div class="yt-thumb video-thumb">
 <img src="//i.ytimg.com/vi/naiLVvuPCAw/mqdefault.jpg" width="196" height="110"/>
 </div>
 Web Applications Today
  • 9.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 frontend code today
  • 10.
    <li class=" yt-uix-shelfslider-item">
 <divclass="yt-lockup yt-lockup-grid yt-lockup-video vve-check clearfix" data-context-item-id="naiLVvuPCAw"
 data-visibility-tracking="CFEQpDAYBSITCM7Or_3JucMCFY6yHAodHk0ANiiOHkCMkLzc7-qi1J0B">
 <div class="yt-lockup-dismissable">
 <div class="yt-lockup-thumbnail contains-addto">
 <a aria-hidden="true" href="/watch?v=naiLVvuPCAw" class=" yt-uix-sessionlink spf-link "
 data-sessionlink="itct=CFEQpDAYBSITCM7Or_3JucMCFY6yHAodHk0ANiiOHjIKZy1oaWdoLXJjaA">
 <div class="yt-thumb video-thumb">
 <img src="//i.ytimg.com/vi/naiLVvuPCAw/mqdefault.jpg" width="196" height="110"/>
 </div>
 <span class="video-time" aria-hidden="true">1:21</span>
 </a>
 <span class="thumb-menu dark-overflow-action-menu video-actions">
 <button onclick=";return false;"
 class="yt-uix-button-reverse flip addto-watch-queue-menu spf-nolink hide-until-delayloaded yt-uix-button yt-uix-button-dark-overflow-action-menu yt-uix-button-size-default yt-uix-button-has-icon no-icon-markup yt-uix-button-empty"
 aria-expanded="false" aria-haspopup="true" type="button">
 <span class="yt-uix-button-arrow yt-sprite"></span>
 <ul class="watch-queue-thumb-menu yt-uix-button-menu yt-uix-button-menu-dark-overflow-action-menu" style="display: none;">
 <li role="menuitem" class="overflow-menu-choice addto-watch-queue-menu-choice addto-watch-queue-play-next yt-uix-button-menu-item"
 data-action="play-next" onclick=";return false;" data-video-ids="naiLVvuPCAw">
 <span class="addto-watch-queue-menu-text">Play next</span>
 </li>
 <li role="menuitem" class="overflow-menu-choice addto-watch-queue-menu-choice addto-watch-queue-play-now yt-uix-button-menu-item"
 data-action="play-now" onclick=";return false;" data-video-ids="naiLVvuPCAw">
 <span class="addto-watch-queue-menu-text">Play now</span>
 </li>
 </ul>
 </button>
 </span>
 <button class="yt-uix-button yt-uix-button-size-small yt-uix-button-default yt-uix-button-empty yt-uix-button-has-icon no-icon-markup addto-button video-actions spf-nolink hide-until-delayloaded addto-watch-later-button-sign-in yt-uix-tooltip"
 type="button" onclick=";return false;" title="Watch Later" role="button"
 data-video-ids="naiLVvuPCAw" data-button-menu-id="shared-addto-watch-later-login"><span
 class="yt-uix-button-arrow yt-sprite"></span></button>
 <button class="yt-uix-button yt-uix-button-size-small yt-uix-button-default yt-uix-button-empty yt-uix-button-has-icon no-icon-markup addto-button addto-queue-button video-actions spf-nolink hide-until-delayloaded addto-tv-queue-button yt-uix- tooltip"
 type="button" onclick=";return false;" title="TV Queue" data-video-ids="naiLVvuPCAw"
 data-style="tv-queue"></button>
 </div>
 <div class="yt-lockup-content">
 <h3 class="yt-lockup-title">
 <a href="/watch?v=naiLVvuPCAw"
 class=" yt-ui-ellipsis yt-ui-ellipsis-2 yt-uix-sessionlink spf-link "
 data-sessionlink="itct=CFEQpDAYBSITCM7Or_3JucMCFY6yHAodHk0ANiiOHjIKZy1oaWdoLXJjaA"
 title="Polizisten hören Helene Fischer&#39;s &#39;Atemlos&#39; im Polizeiauto"
 aria-describedby="description-id-439757"
 dir="ltr">Polizisten hören Helene Fischer&#39;s&#39;Atemlos&#39; im Polizeiauto</a>
 <span class="accessible-description" id="description-id-439757"> - Duration: 1:21.</span>
 </h3>
 <div class="yt-lockup-byline">by <a href="/user/djgreyhair class=" yt-uix-sessionlink spf-link g-hovercard" data-name=""
 data-sessionlink="itct=CFEQpDAYBSITCM7Or_3JucMCFY6yHAodHk0ANiiOHg" data-ytid="UCCBrsuWhYxpwZYSTY7kkB4A">Spass MussSein</a>
 </div>
 <div class="yt-lockup-meta">
 <ul class="yt-lockup-meta-info">
 <li>3,542,577 views</li>
 <li>6 months ago</li>
 </ul>
 </div>
 </div>
 </div>
 </div>
 </li> Web Applications Today
  • 11.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 frontend code tomorrow <shelf title="Popular on YouTube - Switzerland" subscribers=“128,657"> <shelf-grid-item title="iPhone 6 Plus Bend Test" url="https://www.youtube.com/watch?v=znK652H6yQM" thumbnail="https://i.ytimg.com/vi_webp/znK652H6yQM/mqdefault.webp" user="Unbox Therapy" userUrl="https://www.youtube.com/user/unboxtherapy" views="63,732,280" time="4 months ago"> … 
 Web Applications Tomorrow
  • 12.
  • 13.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Spec • Specified by W3C • Current state of spec can be found online: 
 http://www.w3.org/standards/techs/components#w3c_all
  • 14.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Spec • Divided in 4 parts: • HTML Templates • Shadow DOM • Custom Elements • HTML Imports
  • 15.
  • 16.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 <template>
  • 17.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 <template> <div class="activity-stream">
 <h2>Activities</h2>
 
 <div class="activity">
 <img class="icon" src="img/hendrik.jpeg" width="40" height="40">
 <div class="time">Minutes ago</div>
 <div class="content"><a>Hendrik</a> did this again.</div>
 </div> 
 … </div> 
 <div class="activity">
 <img class="icon" src="img/michael.jpeg" width="40" height="40">
 <div class="time">Seconds ago</div>
 <div class="content"><a>Michael</a> had fun coding.</div>
 </div>
  • 18.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 <template> <div class="activity-stream">
 <h2>Activities</h2>
 
 <div class="activity">
 <img class="icon" src="img/hendrik.jpeg" width="40" height="40">
 <div class="time">Minutes ago</div>
 <div class="content"><a>Hendrik</a> did this again.</div>
 </div> 
 … </div> 
 <div class="activity">
 <img class="icon" src="img/michael.jpeg" width="40" height="40">
 <div class="time">Seconds ago</div>
 <div class="content"><a>Michael</a> had fun coding.</div>
 </div>
  • 19.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 <template> <div class="activity">
 
 </div> 
 <img class="icon" src="img/michael.jpeg" width="40" height="40">
 <div class="time">Seconds ago</div>
 <div class="content"><a>Michael</a> had fun coding.</div>
  • 20.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 <template> <template id="activity-template">
 </template> <div class="activity">
 
 </div> template tag 
 <img class="icon" src="img/michael.jpeg" width="40" height="40">
 <div class="time">Seconds ago</div>
 <div class="content"><a>Michael</a> had fun coding.</div>
  • 21.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 <template> <div>
 <img class="icon" src="" width="40" height="40">
 <div class="time"></div>
 <div class="content"></div>
 </div> <template id="activity-template">
 </template> <div class="activity">
 
 </div> copy boilerplate template tag 
 <img class="icon" src="img/michael.jpeg" width="40" height="40">
 <div class="time">Seconds ago</div>
 <div class="content"><a>Michael</a> had fun coding.</div>
  • 22.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 <template> <div>
 <img class="icon" src="" width="40" height="40">
 <div class="time"></div>
 <div class="content"></div>
 </div> <template id="activity-template">
 </template> <div class="activity">
 
 </div> copy boilerplate template tag
  • 23.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 <template> <template id="activity-template">
 <div>
 <img class="icon" src="" width="40" height="40">
 <div class="time"></div>
 <div class="content"></div>
 </div>
 </template>
  • 24.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 <template> <template id="activity-template">
 <div>
 <img class="icon" src="" width="40" height="40">
 <div class="time"></div>
 <div class="content"></div>
 </div>
 </template> var template = document.querySelector('#activity-template');
  • 25.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 <template> <template id="activity-template">
 <div>
 <img class="icon" src="" width="40" height="40">
 <div class="time"></div>
 <div class="content"></div>
 </div>
 </template> var template = document.querySelector('#activity-template'); var clone = document.importNode(template.content, true); use content property
  • 26.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 <template> document.body.appendChild(clone); <template id="activity-template">
 <div>
 <img class="icon" src="" width="40" height="40">
 <div class="time"></div>
 <div class="content"></div>
 </div>
 </template> var template = document.querySelector('#activity-template'); var clone = document.importNode(template.content, true); use content property
  • 27.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 <template> <template id="activity-template">
 <div>
 <img class="icon" ng-src="{{item.iconSrc}}" width="40" height="40">
 <div class="time">{{item.time}}</div>
 <div class="content">{{item.content}}</div>
 </div>
 </template>
  • 28.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 <template> <template id="activity-template">
 <div>
 <img class="icon" ng-src="{{item.iconSrc}}" width="40" height="40">
 <div class="time">{{item.time}}</div>
 <div class="content">{{item.content}}</div>
 </div>
 </template> No Data Binding
  • 29.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 <template> 22+ 26+ and Android 4.4+ 7.1+ 15+
  • 30.
  • 31.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom Web Component
  • 32.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom ".content"".content"
  • 33.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom ".content"".content" document.querySelector(".content")
  • 34.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom ".content"".content" document.querySelector(".content")
  • 35.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom ".content"".content" .content { color: blue; } document.querySelector(".content")
  • 36.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom ".content"".content" .content { color: blue; } document.querySelector(".content")
  • 37.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom
  • 38.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom
  • 39.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom Host Root
  • 40.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom visible to
 the user
  • 41.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom visible to
 the user used during rendering
  • 42.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom
  • 43.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom
  • 44.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom document.querySelector(".content") .content { color: blue; } ".content" ".content"
  • 45.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom document.querySelector(".content") .content { color: blue; } ".content" ".content"
  • 46.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom Host
  • 47.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom var root = host.createShadowRoot(); Host
  • 48.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom var root = host.createShadowRoot(); Host Root
  • 49.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom var root = host.createShadowRoot(); Host Root root.appendChild(child1); root.appendChild(child2);
  • 50.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom var root = host.createShadowRoot(); Host Root root.appendChild(child1); root.appendChild(child2);
  • 51.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom Host
  • 52.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Domvar root = host.createShadowRoot(); Host
  • 53.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Domvar root = host.createShadowRoot(); Host Root
  • 54.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Domvar root = host.createShadowRoot(); Host Root var clone = document.importNode( template.content, true);
  • 55.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Domvar root = host.createShadowRoot(); Host Root var clone = document.importNode( template.content, true); Clone
  • 56.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Domvar root = host.createShadowRoot(); Host Root var clone = document.importNode( template.content, true); root.appendChild(clone); Clone
  • 57.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Domvar root = host.createShadowRoot(); Host Root var clone = document.importNode( template.content, true); root.appendChild(clone); Clone
  • 58.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Shadow Dom 25+ and Android 4.4+ 15+
  • 59.
  • 60.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elements <div class="activity"> <a>Michael</a> had fun coding. </div> How do we store the icon source and time? What is a <div> with the class “activity” anyway?
  • 61.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elements <div class="activity"> <a>Michael</a> had fun coding. </div>
  • 62.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elements <activity-card iconSrc="img/michael.jpg" time="Seconds ago"> <a>Michael</a> had fun coding. </activity-card> <div class="activity"> <a>Michael</a> had fun coding. </div>
  • 63.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elements var activityCardPrototype = Object.create(HTMLElement.prototype);
  • 64.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elements var activityCardPrototype = Object.create(HTMLElement.prototype); Rough translation to Java class ActivityCard extends HTMLElement {}; Class<ActivityCard> activityCardClass = ActivityCard.class;
  • 65.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elements var activityCardPrototype = Object.create(HTMLElement.prototype); Rough translation to Java class ActivityCard extends HTMLElement {}; Class<ActivityCard> activityCardClass = ActivityCard.class; var options = {prototype: activityPrototype}
  • 66.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elements var activityCardPrototype = Object.create(HTMLElement.prototype); Rough translation to Java class ActivityCard extends HTMLElement {}; Class<ActivityCard> activityCardClass = ActivityCard.class; ElementRegistrationOptions options = 
 new ElementRegistrationOptions(activityCardClass); var options = {prototype: activityPrototype}
  • 67.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elements document.registerElement("activity-card", options); var activityCardPrototype = Object.create(HTMLElement.prototype); Rough translation to Java class ActivityCard extends HTMLElement {}; Class<ActivityCard> activityCardClass = ActivityCard.class; ElementRegistrationOptions options = 
 new ElementRegistrationOptions(activityCardClass); var options = {prototype: activityPrototype}
  • 68.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elements document.registerElement("activity-card", options); var activityCardPrototype = Object.create(HTMLElement.prototype); document.registerElement("activity-card", options); Rough translation to Java class ActivityCard extends HTMLElement {}; Class<ActivityCard> activityCardClass = ActivityCard.class; ElementRegistrationOptions options = 
 new ElementRegistrationOptions(activityCardClass); var options = {prototype: activityPrototype}
  • 69.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elements document.registerElement("activity-card", options); var activityCardPrototype = Object.create(HTMLElement.prototype); var options = {prototype: activityPrototype}
  • 70.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elements document.registerElement("activity-card", options); var activityCardPrototype = Object.create(HTMLElement.prototype); var options = {prototype: activityPrototype} <activity-card iconSrc="img/michael.jpg" time="Seconds ago"> <a>Michael</a> had fun coding. </activity-card>
  • 71.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elements create attach detach change createdCallback attachedCallback detachedCallback attributeChangedCallback
 (attrName, oldVal, newVal)
  • 72.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elements
  • 73.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype);
  • 74.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype); activityPrototype.createdCallback = function() {
  • 75.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype); activityPrototype.createdCallback = function() { var template = $("#activity-template");
  • 76.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype); activityPrototype.createdCallback = function() { var template = $("#activity-template"); var clone = document.importNode(template.content, true);
  • 77.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype); activityPrototype.createdCallback = function() { var template = $("#activity-template"); var clone = document.importNode(template.content, true); var host = $(this);
  • 78.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype); activityPrototype.createdCallback = function() { var template = $("#activity-template"); var clone = document.importNode(template.content, true); var host = $(this); $(".icon", clone).attr("src", host.attr("iconSrc"));
  • 79.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype); activityPrototype.createdCallback = function() { var template = $("#activity-template"); var clone = document.importNode(template.content, true); var host = $(this); $(".icon", clone).attr("src", host.attr("iconSrc")); $(".time", clone).text(host.attr("time"));
  • 80.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype); activityPrototype.createdCallback = function() { var template = $("#activity-template"); var clone = document.importNode(template.content, true); var host = $(this); $(".icon", clone).attr("src", host.attr("iconSrc")); $(".time", clone).text(host.attr("time")); var shadow = this.createShadowRoot();
  • 81.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype); activityPrototype.createdCallback = function() { var template = $("#activity-template"); var clone = document.importNode(template.content, true); var host = $(this); $(".icon", clone).attr("src", host.attr("iconSrc")); $(".time", clone).text(host.attr("time")); var shadow = this.createShadowRoot(); shadow.appendChild(clone); };
  • 82.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elementsvar activityPrototype = Object.create(HTMLElement.prototype); activityPrototype.createdCallback = function() { var template = $("#activity-template"); var clone = document.importNode(template.content, true); var host = $(this); $(".icon", clone).attr("src", host.attr("iconSrc")); $(".time", clone).text(host.attr("time")); var shadow = this.createShadowRoot(); shadow.appendChild(clone); }; document.registerElement("activity-card", {prototype: activityPrototype});
  • 83.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Elements 35+ and Android 4.4.4+ 26+
  • 84.
  • 85.
    <!DOCTYPE html>
 <html>
 <head lang="en">
 <metacharset="UTF-8">
 <title>Activity Stream - Standard Web Component</title>
 <link href="stylesheet.css" rel="stylesheet">
 <script src="bower_components/jquery/dist/jquery.min.js"></script>
 </head>
 <body>
 <template>
 <style>
 * {
 font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
 }
 .activity {
 width: 500px;
 height: 40px;
 padding: 10px;
 background-color: #f0f8ff;
 font-size: small;
 margin: 10px 0;
 }
 .activity .icon {
 float: left;
 border-radius: 100%;
 }
 
 .activity .time {
 float: right;
 color: #b7b7b7;
 font-style: italic;
 }
 .activity .content {
 margin-left: 60px;
 }
 </style>
 
 <div class="activity">
 <img class="icon" src="" width="40" height="40">
 <div class="time"></div>
 <div class="content"><content></content></div>
 </div>
 </template>
 
 
 <script>
 
 var activityPrototype = Object.create(HTMLElement.prototype);
 
 activityPrototype.createdCallback = function() {
 var template = document.querySelector('template');
 var clone = document.importNode(template.content, true);
 
 var host = $(this);
 $(".icon", clone).attr("src", host.attr("iconSrc"));
 $(".time", clone).text(host.attr("time"));
 
 var shadowRoot = this.createShadowRoot();
 shadowRoot.appendChild(clone);
 };
 
 // Register our new element
 document.registerElement('activity-card', {
 prototype: activityPrototype
 });
 </script>
 
 <div class="activity-stream">
 <h2>Activities</h2>
 <activity-card iconSrc="../img/michael.jpeg" time="Seconds ago">
 <a href="profiles/michael">Michael</a> had fun writing web components.
 </activity-card>
 <activity-card iconSrc="../img/hendrick.jpeg" time="Minutes ago">
 <a href="profiles/hendrick">Hendrick</a> blogged on <a href="http://guigarage.com">GuiGarage</a>.
 </activity-card>
 <activity-card iconSrc="../img/michael.jpeg" time="1 hour ago">
 <a href="profiles/michael">Michael</a> needed an extra large cup of coffee.
 </activity-card>
 <activity-card iconSrc="../img/hendrick.jpeg" time="Yesterday">
 <a href="profiles/hendrick">Hendrick</a> watched a movie.
 </activity-card>
 </div>
 </body>
 </html>
  • 86.
    <!DOCTYPE html>
 <html>
 <head lang="en">
 <metacharset="UTF-8">
 <title>Activity Stream - Standard Web Component</title>
 <link href="stylesheet.css" rel="stylesheet">
 <script src="bower_components/jquery/dist/jquery.min.js"></script>
 </head>
 <body>
 <template>
 <style>
 * {
 font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
 }
 .activity {
 width: 500px;
 height: 40px;
 padding: 10px;
 background-color: #f0f8ff;
 font-size: small;
 margin: 10px 0;
 }
 .activity .icon {
 float: left;
 border-radius: 100%;
 }
 
 .activity .time {
 float: right;
 color: #b7b7b7;
 font-style: italic;
 }
 .activity .content {
 margin-left: 60px;
 }
 </style>
 
 <div class="activity">
 <img class="icon" src="" width="40" height="40">
 <div class="time"></div>
 <div class="content"><content></content></div>
 </div>
 </template>
 
 
 <script>
 
 var activityPrototype = Object.create(HTMLElement.prototype);
 
 activityPrototype.createdCallback = function() {
 var template = document.querySelector('template');
 var clone = document.importNode(template.content, true);
 
 var host = $(this);
 $(".icon", clone).attr("src", host.attr("iconSrc"));
 $(".time", clone).text(host.attr("time"));
 
 var shadowRoot = this.createShadowRoot();
 shadowRoot.appendChild(clone);
 };
 
 // Register our new element
 document.registerElement('activity-card', {
 prototype: activityPrototype
 });
 </script>
 
 <div class="activity-stream">
 <h2>Activities</h2>
 <activity-card iconSrc="../img/michael.jpeg" time="Seconds ago">
 <a href="profiles/michael">Michael</a> had fun writing web components.
 </activity-card>
 <activity-card iconSrc="../img/hendrick.jpeg" time="Minutes ago">
 <a href="profiles/hendrick">Hendrick</a> blogged on <a href="http://guigarage.com">GuiGarage</a>.
 </activity-card>
 <activity-card iconSrc="../img/michael.jpeg" time="1 hour ago">
 <a href="profiles/michael">Michael</a> needed an extra large cup of coffee.
 </activity-card>
 <activity-card iconSrc="../img/hendrick.jpeg" time="Yesterday">
 <a href="profiles/hendrick">Hendrick</a> watched a movie.
 </activity-card>
 </div>
 </body>
 </html> Component Code Application Code Application Code
  • 87.
  • 88.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Html Import <!DOCTYPE html>
 <html>
 <head lang="en">
 <meta charset="UTF-8">
 <title>Activity Stream - Standard Web Component</title>
 <link href="stylesheet.css" rel="stylesheet">
 <script src="bower_components/jquery/dist/jquery.min.js"></script>
 </head>
 <body>
 <div class="activity-stream">
 <h2>Activities</h2>
 <activity-card iconSrc="../img/michael.jpeg" time="Seconds ago">
 <a href="profiles/michael">Michael</a> had fun writing web components.
 </activity-card>
 <activity-card iconSrc="../img/hendrick.jpeg" time="Minutes ago">
 <a href="profiles/hendrick">Hendrick</a> blogged on <a href="http://guigarage.com">GuiGarage</a>.
 </activity-card>
 <activity-card iconSrc="../img/michael.jpeg" time="1 hour ago">
 <a href="profiles/michael">Michael</a> needed an extra large cup of coffee.
 </activity-card>
 <activity-card iconSrc="../img/hendrick.jpeg" time="Yesterday">
 <a href="profiles/hendrick">Hendrick</a> watched a movie.
 </activity-card>
 </div>
 </body>
 </html> <template>
 <style>
 * {
 font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
 }
 .activity {
 width: 500px;
 height: 40px;
 padding: 10px;
 background-color: #f0f8ff;
 font-size: small;
 margin: 10px 0;
 }
 .activity .icon {
 float: left;
 border-radius: 100%;
 }
 
 .activity .time {
 float: right;
 color: #b7b7b7;
 font-style: italic;
 }
 .activity .content {
 margin-left: 60px;
 }
 </style>
 
 <div class="activity">
 <img class="icon" src="" width="40" height="40">
 <div class="time"></div>
 <div class="content"><content></content></div>
 </div>
 </template>
 
 
 <script>
 
 var activityPrototype = Object.create(HTMLElement.prototype);
 
 activityPrototype.createdCallback = function() {
 var template = document.querySelector('template');
 var clone = document.importNode(template.content, true);
 
 var host = $(this);
 $(".icon", clone).attr("src", host.attr("iconSrc"));
 $(".time", clone).text(host.attr("time"));
 
 var shadowRoot = this.createShadowRoot();
 shadowRoot.appendChild(clone);
 };
 
 // Register our new element
 document.registerElement('activity-card', {
 prototype: activityPrototype
 });
 </script>
  • 89.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Html Import <!DOCTYPE html>
 <html>
 <head lang="en">
 <meta charset="UTF-8">
 <title>Activity Stream - Standard Web Component</title>
 <link href="stylesheet.css" rel="stylesheet">
 <script src="bower_components/jquery/dist/jquery.min.js"></script>
 </head>
 <body>
 <div class="activity-stream">
 <h2>Activities</h2>
 <activity-card iconSrc="../img/michael.jpeg" time="Seconds ago">
 <a href="profiles/michael">Michael</a> had fun writing web components.
 </activity-card>
 <activity-card iconSrc="../img/hendrick.jpeg" time="Minutes ago">
 <a href="profiles/hendrick">Hendrick</a> blogged on <a href="http://guigarage.com">GuiGarage</a>.
 </activity-card>
 <activity-card iconSrc="../img/michael.jpeg" time="1 hour ago">
 <a href="profiles/michael">Michael</a> needed an extra large cup of coffee.
 </activity-card>
 <activity-card iconSrc="../img/hendrick.jpeg" time="Yesterday">
 <a href="profiles/hendrick">Hendrick</a> watched a movie.
 </activity-card>
 </div>
 </body>
 </html> <template>
 <style>
 * {
 font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
 }
 .activity {
 width: 500px;
 height: 40px;
 padding: 10px;
 background-color: #f0f8ff;
 font-size: small;
 margin: 10px 0;
 }
 .activity .icon {
 float: left;
 border-radius: 100%;
 }
 
 .activity .time {
 float: right;
 color: #b7b7b7;
 font-style: italic;
 }
 .activity .content {
 margin-left: 60px;
 }
 </style>
 
 <div class="activity">
 <img class="icon" src="" width="40" height="40">
 <div class="time"></div>
 <div class="content"><content></content></div>
 </div>
 </template>
 
 
 <script>
 
 var activityPrototype = Object.create(HTMLElement.prototype);
 
 activityPrototype.createdCallback = function() {
 var template = document.querySelector('template');
 var clone = document.importNode(template.content, true);
 
 var host = $(this);
 $(".icon", clone).attr("src", host.attr("iconSrc"));
 $(".time", clone).text(host.attr("time"));
 
 var shadowRoot = this.createShadowRoot();
 shadowRoot.appendChild(clone);
 };
 
 // Register our new element
 document.registerElement('activity-card', {
 prototype: activityPrototype
 });
 </script> activity-card.html
  • 90.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Html Import <!DOCTYPE html>
 <html>
 <head lang="en">
 <meta charset="UTF-8">
 <title>Activity Stream - Standard Web Component</title>
 <link href="stylesheet.css" rel="stylesheet">
 <script src="bower_components/jquery/dist/jquery.min.js"></script>
 </head>
 <body>
 <div class="activity-stream">
 <h2>Activities</h2>
 <activity-card iconSrc="../img/michael.jpeg" time="Seconds ago">
 <a href="profiles/michael">Michael</a> had fun writing web components.
 </activity-card>
 <activity-card iconSrc="../img/hendrick.jpeg" time="Minutes ago">
 <a href="profiles/hendrick">Hendrick</a> blogged on <a href="http://guigarage.com">GuiGarage</a>.
 </activity-card>
 <activity-card iconSrc="../img/michael.jpeg" time="1 hour ago">
 <a href="profiles/michael">Michael</a> needed an extra large cup of coffee.
 </activity-card>
 <activity-card iconSrc="../img/hendrick.jpeg" time="Yesterday">
 <a href="profiles/hendrick">Hendrick</a> watched a movie.
 </activity-card>
 </div>
 </body>
 </html> <template>
 <style>
 * {
 font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
 }
 .activity {
 width: 500px;
 height: 40px;
 padding: 10px;
 background-color: #f0f8ff;
 font-size: small;
 margin: 10px 0;
 }
 .activity .icon {
 float: left;
 border-radius: 100%;
 }
 
 .activity .time {
 float: right;
 color: #b7b7b7;
 font-style: italic;
 }
 .activity .content {
 margin-left: 60px;
 }
 </style>
 
 <div class="activity">
 <img class="icon" src="" width="40" height="40">
 <div class="time"></div>
 <div class="content"><content></content></div>
 </div>
 </template>
 
 
 <script>
 
 var activityPrototype = Object.create(HTMLElement.prototype);
 
 activityPrototype.createdCallback = function() {
 var template = document.querySelector('template');
 var clone = document.importNode(template.content, true);
 
 var host = $(this);
 $(".icon", clone).attr("src", host.attr("iconSrc"));
 $(".time", clone).text(host.attr("time"));
 
 var shadowRoot = this.createShadowRoot();
 shadowRoot.appendChild(clone);
 };
 
 // Register our new element
 document.registerElement('activity-card', {
 prototype: activityPrototype
 });
 </script> activity-card.html <link rel="import" href="activity-card.html">
  • 91.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Html Import 36+ and Android Browser 37 26+
  • 92.
  • 93.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 webcomponent.js • Today not all browsers support the new standards • The community provides a pollyfills to enable web components in browser that have no native support $ bower install --save webcomponentsjs <script src="bower_components/webcomponentsjs/webcomponents.js"></script> install it with bower use it in your code
  • 94.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 webcomponent.js • The polyfills are the junction of X-Tag and Polymer basic libraries • Mozilla created X-Tag as a polyfill to provide web components • Google created Polymer as a polyfill to provide web components
  • 95.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 webcomponent.js • X-Tag and Polymer depends on webcomponents-js • Both libraries provide additional features that are not part of the specification webcomponents.org
  • 96.
  • 97.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Polymer • Adds sugar on top of web components • Easy to use • Extendable • Polymer is created & supported by Google
  • 98.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Polymer • Separated in several parts: • Polymer API • Iron Elements • Paper Elements • … www.polymer-project.org
  • 99.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Polymer
  • 100.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Iron Elements • Iron Elements are low level components • Most Paper UI components base on Iron • Icons, layouts …
  • 101.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Icons
  • 102.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Icons
  • 103.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Google Web Components • Google is building a lot of components (maps, youtube…) <google-chart></google-chart> <google-hangout-button></google-hangout-button>
  • 104.
  • 105.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Polymer Paper • Complete component library based on Material Design
  • 110.
  • 111.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Bower • A package manager for the web • Search for dependencies and install them as packages • Created by Twitter • Open Source www.bower.io
  • 112.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Bower requires npm, node.js and git $ npm install -g bower $ bower init $ bower install --save webcomponentsjs in your project folder download & add module add dependency to bower file
  • 113.
  • 114.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 How to use Components • All components are build as web components • A single component or a set can be added by using bower $ bower install --save Polymer/paper-slider <link rel="import" href="bower_components/paper-slider/paper-slider.html"> import it in HTML
  • 115.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Paper Button • The default Button • shows ripple animation on click <paper-button>flat button</paper-button> <paper-button raised>raised button</paper-button> <paper-button noink>No ripple effect</paper-button>
  • 116.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Paper CheckBox • A styled CheckBox • State can be defined as attribute <paper-checkbox></paper-checkbox> <paper-checkbox checked></paper-checkbox>
  • 117.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Paper Dialog • A dialog • Supports title, modality, actions, … <paper-dialog heading="Title"> <p>Some content</p> </paper-dialog>
  • 118.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Overview
  • 119.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Overview
  • 120.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Layout • HeaderPanel • Toolbar • DrawerPanel • Scaffold
  • 121.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Toolbar • An application toolbar • Toolbar content will be aligned <core-toolbar> <paper-icon-button icon="menu"></paper-icon-button> <div>My Application</div> <span flex></span> <paper-icon-button icon="event"></paper-icon-button> </core-toolbar>
  • 122.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 HeaderPanel • Wrapper around toolbar and content • Toolbar always on top • Content scrollable <core-header-panel flex> <core-toolbar>Title</core-toolbar> <div>content</div> </core-header-panel>
  • 123.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 DrawerPanel • Adds a responsive menu • Defines attributes to open and close the menu • Normally wraps 2 core- header-panel
  • 124.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 DrawerPanel <core-drawer-panel> <core-header-panel drawer> <core-toolbar></core-toolbar> <core-menu> <core-item label="One"></core-item> </core-menu> </core-header-panel> <core-header-panel main> <core-toolbar> <paper-icon-button core-drawer-toggle icon="menu"></paper-icon-button> </core-toolbar> <div>content</div> </core-header-panel> </core-drawer-panel> drawer panel main panel show drawer
  • 125.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Scaffold • Basic skeleton • Best practice to create an application • Contains all the shown features <core-scaffold> <core-header-panel navigation flex> <!-- nav drawer --> </core-header-panel> <span tool>Title</span> <div>content</div> </core-scaffold> defines the drawer defines the main toolbar
  • 126.
  • 127.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Paper Demo • Create a new folder • Install needed modules with Bower $ mkdir app $ cd app $ bower init $ bower install --save PolymerElements/paper-elements
  • 128.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Paper Demo • Create index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> </head> <body>Hello World</body> </html>
  • 129.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Paper Demo • add webcomponents.js • 
<head> . . . <script src=„bower_components/webcomponentsjs/webcomponents.js"> </script> </head>
  • 130.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Paper Demo • add Roboto Font • 
<head> <link rel="import" href=„bower_components/font-roboto/ roboto.html"> <style> html,body { font-family: 'RobotoDraft', sans-serif; } </style> </head>
  • 131.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Paper Demo
  • 132.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Paper Demo • add a header panel with a toolbar <body class="fullbleed layout vertical">
 <paper-header-panel class="flex">
 <paper-toolbar>Title</paper-toolbar>
 </paper-header-panel>
 </body>
 <link rel=„import" href="bower_components/paper-styles/paper-styles.html"> <link rel=„import" href="bower_components/paper-header-panel/paper-header-panel.html"> <link rel="import" href="bower_components/paper-toolbar/paper-toolbar.html">
  • 133.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Paper Demo
  • 134.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Paper Demo • Add some content to the toolbar <link rel=„import" href="bower_components/iron-icons/iron-icons.html"> <link rel="import" href="bower_components/paper-icon-button/paper-icon-button.html"> <paper-toolbar>
 <paper-icon-button icon="menu"></paper-icon-button>
 <span class="flex">Title</span>
 <paper-icon-button icon="add"></paper-icon-button>
 <paper-icon-button icon="remove"></paper-icon-button>
 </paper-toolbar>
  • 135.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Paper Demo
  • 136.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Paper Demo • Add paper elements as content <link rel="import" href=„bower_components/paper-input/paper-input.html"> <link rel="import" href="bower_components/paper-button/paper-button.html"> <div class="layout vertical"> <paper-input label="Name"></paper-input> <paper-input label="Description"></paper-input> <paper-button raised>save</paper-button> </div>
  • 137.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Paper Demo
  • 138.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Paper Demo • Add some padding .content { padding: 20px; } <div class="content layout vertical"> <paper-input label="Name"></paper-input> <paper-input label="Description"></paper-input> <paper-button raised>save</paper-button> </div>
  • 139.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Paper Demo
  • 140.
  • 141.
  • 142.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Components • Polymer can be used to create custom web components • Defines a nice and modern API to create components • Adds several features on top of the spec
  • 143.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 A First Example <link rel=„import" href="bower_components/polymer/polymer.html">
  • 144.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 A First Example <link rel=„import" href="bower_components/polymer/polymer.html"> <dom-module id="dom-element"> </dom-module>
  • 145.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 A First Example <link rel=„import" href="bower_components/polymer/polymer.html"> <dom-module id="dom-element"> <template> <p>I'm a DOM element. This is my local DOM!</p> </template> </dom-module>
  • 146.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 A First Example <link rel=„import" href="bower_components/polymer/polymer.html"> <dom-module id="dom-element"> <template> <p>I'm a DOM element. This is my local DOM!</p> </template> <script> Polymer({is: "dom-element"}); </script> </dom-module>
  • 147.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 • Component name must contain a "-" • Polymer script call must be included • Template is not needed • Once it is created it can be used as custom tag Custom Components
  • 148.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Lifecycle • Polymer defines it’s own lifecycle that is based on the Web Component Spec lifecycle • Callbacks can simply be defined in Polymer
  • 149.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Difference to Spec • created instead of createdCallback • attached instead of attachedCallback • detached instead of detachedCallback • attributeChanged instead of attributeChangedCallback
  • 150.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Additional Callback • Polymer adds an extra callback ready which is invoked when Polymer has finished creating and initializing the element’s local DOM. • The created callback is always called before ready. • The ready callback is always called before attached.
  • 151.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Example<script> Polymer({ is: „dom-element“, ready: function () { console.log('Ready!'); }, detached: function() { console.log(this.localName + '#' + this.id + ' was detached'); }, attributeChanged: function(name, type) { console.log('Attribute ' + name + ' was changed'); } }); </script>
  • 152.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Property • Properties can be specified for a Polymer component • A property can be of the following types: • Boolean, Date, Number, String, Array or Object
  • 153.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Property • Properties can be defined in JavaScript Polymer({ is: 'my-component', properties: { user: String, isHappy: Boolean } });
  • 154.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Property • Properties can be set in JavaScript
 
 
 
 Properties can be set as HTML attribute ready: function () { this.set(‘user‘,’unknown‘); } <my-component user=‘unknown‘></my-component>
  • 155.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Property • Default value can be specified properties: { user: { type: String, value: ‘unknown‘ }, isHappy: Boolean }
  • 156.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Data Binding • binds a property to an attribute of an element
 
 • Use [[prop]] for one-way-binding • Property defines if {{prop}} is one-way or bidirectional binding <child-element name="{{myName}}"></child-element>
  • 157.
  • 158.
  • 159.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0
  • 160.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0
  • 161.
  • 162.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Application Basic Layout • Header with fixed size
 • Resizeable main area
 • Footer with fixed size
  • 163.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Polymer Layout • The Polymer layout is based on flexbox • Use Polymer layout classes to simplify the usage of flexbox
  • 164.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Flexbox • New CSS 3 layout • Flexbox consists of flex containers and flex items. box box box container
  • 165.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Flexbox • Contents can be laid out in any flow direction (leftwards, rightwards, downwards, or even upwards!) • Contents can be laid out linearly along a single (main) axis or wrapped into multiple lines along a secondary (cross) axis • Contents can “flex” their sizes to respond to the available space • …
  • 166.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Flexbox box box box container flex-direction: row; box box box container flex-direction:column;
  • 167.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Flexbox box box box container flex: 0; flex: 0;flex: 1;
  • 168.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Application Basic Layout fix height fix height dynamic height flexbox
  • 169.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Using Flex Box in Polymer • Polymer defines several layout classes • layout: basic class that must be set • horizontal: layout content in a row • vertical: layout content in a column • flex: content will fill space
  • 170.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Polymer Layout Alpha Beta Gamma <div class="horizontal layout"> <div>Alpha</div> <div class="flex">Beta (flex)</div> <div>Gamma</div> </div>
  • 171.
  • 172.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Application Structure • A Polymer application is based on web components • The components define a hierarchy • chat-view component contains several chat-bubble components
  • 173.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Application Structure
  • 174.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Application Structure Yeah! message-view
  • 175.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 chat-bubble Application Structure Yeah! message-view
  • 176.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 chat-view chat-bubble Application Structure Yeah! message-view
  • 177.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 app-view chat-view chat-bubble Application Structure Yeah! message-view
  • 178.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Like building futuristic Matrjoschkas with Lego
  • 179.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Application Structure • The demo will use bower to handle all dependencies • Real applications should use a build script • like Gulp or Grunt
  • 180.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 index.html • add web components polyfill script • Import basic dependencies like Roboto- Font and Polymer layouts • body contains only one web component: the application
  • 181.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 imports 
 <script src="bower_components/webcomponentsjs/webcomponents.js"></script>
 
 <link rel="import" href="bower_components/paper-styles/paper-styles.html">
 <link rel="import" href="bower_components/font-roboto/roboto.html">

  • 182.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 imports 
 <script src="bower_components/webcomponentsjs/webcomponents.js"></script>
 
 <link rel="import" href="bower_components/paper-styles/paper-styles.html">
 <link rel="import" href="bower_components/font-roboto/roboto.html">
 web components polyfill font and layouts
  • 183.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 component-xy.html • Contains the definition of one web component • All components that are needed internally should be imported
  • 184.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Workspace bower.json index.html chat-bubble.html chat-view.html chat-header.html chat-footer.html chat-app.html
  • 185.
  • 186.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Chat Bubble Sender This is the chat message. The size of the bubble should fit to this message. Next to normal text emojis can be part of a message: 😊 5 min ago
  • 187.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Chat Bubble Sender This is the chat message. The size of the bubble should fit to this message. Next to normal text emojis can be part of a message: 😊 5 min ago depends on parent width dependsontextlength
  • 188.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Chat Bubble Sender This is the chat message. The size of the bubble should fit to this message. Next to normal text emojis can be part of a message: 😊 5 min ago dependsontext length fix fix
  • 189.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Chat Bubble Sender This is the chat message. The size of the bubble should fit to this message. Next to normal text emojis can be part of a message: 😊 5 min ago fix
  • 190.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Chat Bubble
  • 191.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Chat Bubble <div id="bubble"><div> #bubble {
 background-color: #F2F2F2;
 border-radius: 5px;
 }
  • 192.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Chat Bubble Sender This is the chat message. The size of the bubble should fit to this message. Next to normal text emojis can be part of a message: 😊 5 min ago
  • 193.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Chat Bubble <div id="bubble"><div> #bubble {
 background-color: #F2F2F2;
 border-radius: 5px; padding: 2px 12px 2px 12px; }
  • 194.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Chat Bubble
  • 195.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 CSS ::after Selector p::after {
 content: " - Remember this";
 } • The ::after selector inserts something after the content of each selected element(s). • Use the content property to specify the content to insert.
  • 196.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Chat Bubble #bubble::after {
 background-color: #F2F2F2;
 display: block;
 position: absolute;
 content: "00a0";
 height: 16px;
 width: 20px;
 bottom: 11px;
 transform: rotate(29deg) skew(-35deg);
 }
  • 197.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Chat Bubble Web Component <dom-module id=„chat-bubble"> <style> #bubble { . . . } </style> 
 <template> <div id=„bubble"> . . . </div> </template> 
 </dom-module> 
 <script> Polymer({
 is: "chat-bubble" }); </script>
  • 198.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Chat Bubble Attributes • Sender & message should be dynamic • Can be defined as attributes of the component • Use Polymer properties properties: {
 text: String,
 sender: String
 }
  • 199.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Problem
  • 200.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 configure Bubble with CSS #bubble {
 . . .
 } • We can specify 2 separate CSS classes: me and you .me { . . . } .you { . . . }
  • 201.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 • We can dynamically change the CCS class in JS code • Access bubble div in Polymer
 • Mutate class list change Css class bubbleDiv.classList.remove('me');
 bubbleDiv.classList.add('you'); var bubbleDiv = this.$.bubble; id of the div
  • 202.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 • Polymer provides observers for properties
 
 • Observer will be called whenever property values changes Property Observer me: { type: Boolean,
 observer: ‚_senderChanged' } _senderChanged: function (newValue, oldValue) {
 this.updateStyleClass(newValue);
 }
  • 203.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 • The initial boolean property value reflects if a HTML attribute is set use boolean property <chat-bubble me></chat-bubble> <chat-bubble></chat-bubble> „me“ property == true „me“ property == false
  • 204.
  • 205.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Chat View • Should contain a list of chat bubbles • Scrollable • based on data array (JSON)
  • 206.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Polymer Iron • List of low level components • Define behavior • Don’t define theme / skin
  • 207.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0
  • 208.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 iron-list • Defines a list that can be scrolled • Can contain thousands of elements. Only visible area is rendered • Define a template for each cell
  • 209.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 iron-list <iron-list items="[[data]]" as="item">
 <template>
 <chat-bubble text=„[[item.message]]" …></chat-bubble>
 </template>
 </iron-list>
  • 210.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 provide dummy data <iron-ajax url="data.json" last-response="{{messages}}" auto></iron-ajax>
 • Polymer provides Iron Element to load JSON data
  • 211.
  • 212.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Centered Text • The name should be centered • Layout should not be effected by other nodes .centered {
 top: 18px;
 left: 0;
 position:absolute;
 width: 100%;
 } .title {
 font-size: 22px;
 text-align:center;
 } parent of text text
  • 213.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Rounded Image • Avatar image should be rounded .avatar {
 width: 64px;
 height: 64px;
 border-radius: 32px;
 border-style: solid;
 border-width: 1px;
 border-color: lightgrey;
 }
  • 214.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Dynamic content • Add some Polymer properties
 
 
 • Use them inline
 Properties: {
 title: String,
 state: String
 } <div class="centered vertical layout">
 <div class="title">{{title}}</div>
 <div class="subtitle">{{state}}</div>
 </div>
  • 215.
  • 216.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Textbox • <input> can be styled with CSS • Polymer provides a behavior to add data binding to a normal input <input is="iron-input" value="{{message::input}}">
  • 217.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Custom Button • Call a internal web component function when the button is clicked <button on-click="sendMyMessage">send</button> Polymer({
 is: "input-view",
 sendMyMessage: function (e) {…}
 });
  • 218.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Polymer events • Web Components can fire events
 • Observer can be added
 • Hint: trigger a resize for iron-list when content changes:
 this.fire('message-send', {message: this.message}); <input-view on-message-send="send"></input-view> this.$.itemsList.fire('resize');
  • 219.
  • 220.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 About Emojis • All emojis are defined by a a unicode character
  • 221.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Emojis in HTML • Most OS provide a font to render emojis • As long as the browser supports unicode and your files are encoded in unicode you can use them
  • 222.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Parse Emojis • Cool lib with word - emoji mapping can be found here: 
 github.com/muan/emojilib • A Polymer Emoji selector can be found here:
 github.com/notwaldorf/emoji-selector
  • 223.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Emojis in the chat var converted = '';
 var words = input.split(' ');
 for (var i = 0; i < words.length; i++) {
 var emoji = getMeAnEmoji(words[i]);
 if(emoji != '') {
 converted = converted + ' ' + emoji;
 } else {
 converted = converted + ' ' + words[i];
 }
 }
  • 224.
  • 226.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Dolphin Platform • Enterprise Framework with Presentation Model pattern • Server centric logic • Spring and JavaEE integration
  • 227.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Dolphin Platform • JavaFX, AngularJS & Google Polymer client APIs
 
 
 
 
 … More will come
  • 228.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Dolphin Platform
  • 229.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Model • Defined in Java • Hierarchical models are no problem • Full observable • Collection support
  • 230.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Model @DolphinBean public class MyModel { private Property<String> name; public Property<String> nameProperty() {return name;} } Dolphin Platform propere can be used on client and server This is NOT a JFXProperty
  • 231.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Controller • Controller is defined on the server • Will be managed by the container (Spring, JavaEE, …) • Full CDI support
  • 232.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Controller @DolphinController public class MyController { @DolphinModel private MyModel model; @PostConstruct public void init() { model.nameProperty().onChange(e -> System.out.println(„CHANGE“)); } } Inject the model Use containerfeatures
  • 233.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 View • The smallest part ;) • Use the complete UI Toolkit power • Simply bind your view to the model • Trigger controller actions
  • 234.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 View <dom-module id="my-view"> <template> <paper-input label="Task name" value="{{model.name}}"></paper-input> </template> </dom-module> <script> Polymer({ is: "my-view", behaviors: [clientContext.createBehavior('MyController')] }); </script> Dolphin Platform providesPolymer behavior Server controller Dolphin Platformmodel
  • 235.
  • 236.
    PolymerWeb Components &by Sending a message Client Server
  • 237.
    PolymerWeb Components &by Sending a message Client Server call DolphinAction
  • 238.
    PolymerWeb Components &by Sending a message Client Server Event Bus call DolphinAction
  • 239.
    PolymerWeb Components &by Sending a message Client Server Event Bus call DolphinAction publish
  • 240.
    PolymerWeb Components &by Sending a message Client Server Event Bus call DolphinAction publish
  • 241.
    PolymerWeb Components &by Sending a message Client Server Event Bus call DolphinAction publish notify
  • 242.
    PolymerWeb Components &by Sending a message Client Presentation Model Server Event Bus call DolphinAction publish notify
  • 243.
    PolymerWeb Components &by Sending a message Client Presentation Model Server Event Bus call DolphinAction publish notifyupdate
  • 244.
    PolymerWeb Components &by Sending a message Client Presentation Model Server Event Bus call DolphinAction publish notifyupdate
  • 245.
    PolymerWeb Components &by Sending a message Client Presentation Model Server Event Bus call DolphinAction publish notifyupdate synced automatically
  • 246.
    PolymerWeb Components &by client code diff
  • 247.
  • 248.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Additional Topics • Behaviors • Animations • Custom CSS properties • DOM manipulation
  • 249.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Additional Topics • Polymer contains more features • Explorer the Polymer Catalog
 • Read the documentation https://elements.polymer-project.org https://www.polymer-project.org/1.0/docs/
  • 250.
  • 251.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Real World • Todo
  • 252.
  • 253.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Polymer Starter Kit • Fully functional mini-application • Defines application structure • Contains many useful configurations
 (e.g. for gitignore, jshint, travis) • Sophisticated build script • Sidenote: all files contain copyright headers
  • 254.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Polymer Starter Kit • Minification ( js, css, images) • Inlining of HTML Imports • Cache Config for Offline Usage • Local Server (with browser-sync) • Testing
  • 255.
  • 256.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester npm install -g web-component-tester wct Installation Usage
  • 257.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester • Integrates Mocha, Chai, and Sinon • Runs with Selenium • Integration with Sauce Labs provided • By default runs all tests in test/ • Tasks for grunt and gulp available
 (though gulp integration is sub-optimal)
  • 258.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester <head>
 <meta charset="utf-8">
 <script src="../bower_components/webcomponentsjs/webcomponents.min.js"> </script>
 <script src="/web-component-tester/browser.js"></script>
 <link rel="import" href="../chat-bubble.html">
 </head>
  • 259.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester <head>
 <meta charset="utf-8">
 <script src="../bower_components/webcomponentsjs/webcomponents.min.js"> </script>
 <script src="/web-component-tester/browser.js"></script>
 <link rel="import" href="../chat-bubble.html">
 </head> web component polyfill
  • 260.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester <head>
 <meta charset="utf-8">
 <script src="../bower_components/webcomponentsjs/webcomponents.min.js"> </script>
 <script src="/web-component-tester/browser.js"></script>
 <link rel="import" href="../chat-bubble.html">
 </head>
  • 261.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester <head>
 <meta charset="utf-8">
 <script src="../bower_components/webcomponentsjs/webcomponents.min.js"> </script>
 <script src="/web-component-tester/browser.js"></script>
 <link rel="import" href="../chat-bubble.html">
 </head> provided by wct
  • 262.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester <head>
 <meta charset="utf-8">
 <script src="../bower_components/webcomponentsjs/webcomponents.min.js"> </script>
 <script src="/web-component-tester/browser.js"></script>
 <link rel="import" href="../chat-bubble.html">
 </head>
  • 263.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester <head>
 <meta charset="utf-8">
 <script src="../bower_components/webcomponentsjs/webcomponents.min.js"> </script>
 <script src="/web-component-tester/browser.js"></script>
 <link rel="import" href="../chat-bubble.html">
 </head> component under test
  • 264.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester <body> <test-fixture id="chatBubbleFixture">
 <template>
 <chat-bubble></chat-bubble>
 </template>
 </test-fixture> ...
  • 265.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester <body> <test-fixture id="chatBubbleFixture">
 <template>
 <chat-bubble></chat-bubble>
 </template>
 </test-fixture> ... provided by wct
  • 266.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester <body> <test-fixture id="chatBubbleFixture">
 <template>
 <chat-bubble></chat-bubble>
 </template>
 </test-fixture> ...
  • 267.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester <body> <test-fixture id="chatBubbleFixture">
 <template>
 <chat-bubble></chat-bubble>
 </template>
 </test-fixture> ... web component under test
  • 268.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester<script>
 describe('<chat-bubble>', function() {
 it('should show the sender', function(done) {
 var chatBubble = fixture('chatBubbleFixture');
 chatBubble.set('sender', 'Test Sender');
 setTimeout(function () {
 expect(chatBubble.$$('.sender')) .to.have.property('textContent')
 .that.contains('Test Sender');
 done();
 });
 });
 });
 </script>
  • 269.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester<script>
 describe('<chat-bubble>', function() {
 it('should show the sender', function(done) {
 var chatBubble = fixture('chatBubbleFixture');
 chatBubble.set('sender', 'Test Sender');
 setTimeout(function () {
 expect(chatBubble.$$('.sender')) .to.have.property('textContent')
 .that.contains('Test Sender');
 done();
 });
 });
 });
 </script> create component
  • 270.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester <script>
 describe('<chat-bubble>', function() {
 it('should show the sender', function(done) {
 var chatBubble = fixture('chatBubbleFixture');
 chatBubble.set('sender', 'Test Sender');
 setTimeout(function () {
 expect(chatBubble.$$('.sender')) .to.have.property('textContent')
 .that.contains('Test Sender');
 done();
 });
 });
 });
 </script>
  • 271.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester <script>
 describe('<chat-bubble>', function() {
 it('should show the sender', function(done) {
 var chatBubble = fixture('chatBubbleFixture');
 chatBubble.set('sender', 'Test Sender');
 setTimeout(function () {
 expect(chatBubble.$$('.sender')) .to.have.property('textContent')
 .that.contains('Test Sender');
 done();
 });
 });
 });
 </script> set property
  • 272.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester<script>
 describe('<chat-bubble>', function() {
 it('should show the sender', function(done) {
 var chatBubble = fixture('chatBubbleFixture');
 chatBubble.set('sender', 'Test Sender');
 setTimeout(function () {
 expect(chatBubble.$$('.sender')) .to.have.property('textContent')
 .that.contains('Test Sender');
 done();
 });
 });
 });
 </script>
  • 273.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester<script>
 describe('<chat-bubble>', function() {
 it('should show the sender', function(done) {
 var chatBubble = fixture('chatBubbleFixture');
 chatBubble.set('sender', 'Test Sender');
 setTimeout(function () {
 expect(chatBubble.$$('.sender')) .to.have.property('textContent')
 .that.contains('Test Sender');
 done();
 });
 });
 });
 </script> needs to be asynchronous
  • 274.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester<script>
 describe('<chat-bubble>', function() {
 it('should show the sender', function(done) {
 var chatBubble = fixture('chatBubbleFixture');
 chatBubble.set('sender', 'Test Sender');
 setTimeout(function () {
 expect(chatBubble.$$('.sender')) .to.have.property('textContent')
 .that.contains('Test Sender');
 done();
 });
 });
 });
 </script>
  • 275.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester<script>
 describe('<chat-bubble>', function() {
 it('should show the sender', function(done) {
 var chatBubble = fixture('chatBubbleFixture');
 chatBubble.set('sender', 'Test Sender');
 setTimeout(function () {
 expect(chatBubble.$$('.sender')) .to.have.property('textContent')
 .that.contains('Test Sender');
 done();
 });
 });
 });
 </script> DOM-query
  • 276.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester module.exports = {
 plugins: {
 sauce: {
 browsers: [
 {
 platform: 'Windows 8.1',
 browserName: 'internet explorer',
 version: '11.0'
 }
 ]
 }
 }
 };
  • 277.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Web Component Tester module.exports = {
 plugins: {
 sauce: {
 browsers: [
 {
 platform: 'Windows 8.1',
 browserName: 'internet explorer',
 version: '11.0'
 }
 ]
 }
 }
 }; environment configuration
  • 278.
  • 279.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Situation • All components are part of our project • We can’t reuse them in other projects • The components are not isolated • Looks like a bad mixup
  • 280.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0
  • 281.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 Wish list • We want reusable components • A component should be independent and isolated • Components can depend on each other / include other custom components • Use a component as a bower dependency
  • 283.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 seed-element • Blueprint for custom component • Defines demo, test, and main section • Web component tester and polyserve integrated
  • 284.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 polyserve • Polymer offers a special web server to create reusable components • serves project files under /components/ {bower-name}/ • other component are served from ./ bower_components/
  • 285.
    PolymerWeb Components &by Questions: https://goo.gl/iZI3l0 polyserve • Your component can refer to external components like your component is in the bower_components folder • Simple to create a github repo for one specific reusable component • Polymer Paper is doing the same
  • 286.