Andreas Argelius
Nov 18, 2015
Engineer originally from Sweden, recently moved to Japan to work with JavaScript development.
Enjoys studying Japanese, eating good food and drinking beer.
Avid runner currently preparing for Yokohama Marathon.
I help make a service called Monaca.
Monaca is ...
A hybrid app UI component library
Some of the features are:
AngularJS
React
<h3>iOS switches</h3>
<ons-switch></ons-switch>
<ons-switch checked></ons-switch>
<ons-switch checked modifier="green"></ons-switch>
<h3>Material Design switches</h3>
<ons-switch modifier="material"></ons-switch>
<ons-switch modifier="material" checked></ons-switch>
All components are custom tags:
Actually Onsen UI is only using the Custom Elements API.
A collection of technologies including...
Elements are defined using
document.registerElement(name, options)
It's a very simple API.
var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function() {
this.innerHTML = 'The Force will be with you.';
setInterval (function () {
this.innerHTML = this.innerHTML ===
'Always.' ? 'The Force will be with you.' : 'Always.';
}.bind(this), 2000);
};
document.registerElement('my-fancy-element', {prototype: proto});
createdCallback()
attachedCallback()
detachedCallback()
attributeChangedCallback()
There are four different lifecycle callbacks:
GitHub is using the Custom Elements API.
From MDN:
Only supported in Chrome!
Polyfill: github.com/webcomponents/webcomponentsjs
class Person {
constructor(name = 'Andreas') {
this.name = 'Andreas';
}
get name() {
return this._name;
}
set name(n) {
if (typeof n !== 'string') {
throw new Error('Name must be a string.');
}
this._name = n;
}
greeting() {
alert(`Hello! My name is ${this.name}!`);
}
}
Introduces constructor, getters, setters, default arguments.
let add = (a, b) => {
return a + b;
};
// Even shorter
add = (a, b) => a + b;
// Nice in functional expressions.
let lengths = names.map((n) => n.length);
// Before
lengths = names.map(function(n) {
return n.length;
});
Yet another way to define functions in JavaScript!
function Person(age) {
var that = this;
that.age = age;
setInterval (function () {
that.age++;
});
}
function Person(age) {
this.age = age;
setInterval (function () {
this.age++;
}.bind(this));
}
function Person(age) {
this.age = age;
setInterval (() => {
this.age++;
});
}
We used to do like this:
Or like this:
Arrow functions bind the lexical "this" value. So we can do like this:
Babel will translate ES2015 code into code that can be interpreted and executed by all modern browers.
'use strict';
var fn = function fn(name) {
console.log('May the force be with you, ' + name);
};
fn('Andreas');
const fn = (name) => {
console.log(`May the force be with you, ${name}`);
};
fn('Andreas');
babel --presets es2015 force.js
class HelloElement extends HTMLElement {
createdElement() {
this.innerHTML = `Hello, ${this.name}!`
}
attributeChangedCallback(name, from, to) {
this.innerHTML = `Hello, ${to}`;
}
get name() {
return this.getAttribute('name') || 'Andreas';
}
}
document.registerElement('hello-there', HelloWorldElement);
Source is available on GitHub
class StarRating extends HTMLElement {
createdCallback() {
const template = doc.querySelector('template') || document.createElement('template');
const clone = document.importNode(template.content, true);
this.createShadowRoot();
this.shadowRoot.appendChild(clone);
this._createStars().forEach((star) => {
this.shadowRoot.appendChild(star);
});
this._colorStars();
}
attributeChangedCallback(name, from, to) {
if (name === 'value') {
this._colorStars();
}
}
get value() {
const v = parseFloat(this.getAttribute('value') || 0);
if (!(v >= 0)) {
return 0;
}
return v;
}
set value(v) {
if (!(parseFloat(v) >= 0)) {
throw new Error('Value must be a number larger or equal to 0.');
}
this.setAttribute('value', v);
}
get max() {
return parseInt (this.getAttribute ('max') || 5);
}
set max(v) {
throw new Error('The maximum value can\'t be changed.');
}
get _stars() {
return Array.from(this.shadowRoot.childNodes)
.filter ((node) => node.nodeName.toLowerCase () === 'span');
}
_createStars() {
const stars = [];
for (let i = 0; i < this.max; i++) {
const star = document.createElement('span');
star.innerHTML = '★';
stars.push(star);
const innerStar = document.createElement('span');
innerStar.innerHTML = '★';
star.appendChild(innerStar);
}
return stars;
}
_colorStars() {
const value = this.value;
let p;
for (var i = 0; i < this.max; i++) {
const star = this._stars[i];
const innerStar = star.children[0];
if (i + 1 <= value) {
innerStar.style.width = '100%';
}
else {
innerStar.style.width = 0;
}
p = value - i;
if (p > 0 && p < 1) {
innerStar.style.width = p * 100 + '%';
}
}
}
}
window.StarRatingElement = document.registerElement('star-rating', StarRating);