first impressions by @GionKunz
Object.observe()
ECMAScript 6
Web Components
the three main web standards behind AngularJS 2
var object = {};
Object.observe(object, function(changeRecords) {
changeRecords.forEach(function(cr) {
console.log(cr.name + ' ' + cr.type);
});
});
object.p1 = 'Property 1';
object.p2 = 'Property 2';
object.p2 = 'Property II';
delete object.p1;
class Person {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(this.name + ': Hi there!');
}
static createPerson(name) {
return new Person(name);
}
}
var gion = new Person('Gion');
gion.sayHello();
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function sayHello() {
console.log(this.name + ': Hi there!');
};
Person.createPerson = function createPerson(name) {
return new Person(name);
};
var gion = new Person('Gion');
gion.sayHello();
class Organism {}
class Person extends Organism {
constructor(name) {
super();
this.name = name;
}
}
class Developer extends Person {
constructor(name, lovesAngular) {
super(name);
this.lovesAngular = lovesAngular;
}
}
var gion = new Developer('Gion', true);
console.log(gion);
var num = 100;
var str = `The square root of ${num} is ${Math.sqrt(num)}`;
console.log(str);
var className = 'my-class';
var title = 'Welcome';
var html = `
<div class="${className}">
<h1>${title}</h1>
</div>
`;
console.log(html);
var num = 100;
var str = 'The square root of ' + num + ' is ' + Math.sqrt(num);
console.log(str);
var className = 'my-class';
var title = 'Welcome';
var html = '\n' +
'<div class="' + className + '">\n' +
' <h1>' + title + '</h1>\n' +
'</div>\n';
console.log(html);
Custom Elements
HTML Imports
Templates
Shadow DOM
<body>
<template id="template">
<h1>This is a template!</h1>
</template>
</body>
var template = document.querySelector('#template');
var instance = document.importNode(template.content, true);
document.body.appendChild(instance);
the video element is shadow dom: http://camendesign.com/code/video_for_everybody/test.html
<body>
<div id="host"></div>
</body>
var host = document.querySelector('#host');
var root = host.createShadowRoot();
var elem = document.createElement('h1');
elem.textContent = 'Bombaclat!';
root.appendChild(elem);
Meta Annotations
Template Strings
Type Annotations
@Component({
selector: 'app'
})
@View({
template: `
<div>
<h1>Hello {{ name }}!</h1>
</div>
`
})
class App {
name:string;
constructor() {
this.name = 'World';
}
}
desugaring from AtScript before moving to TypeScript with ES7 like decorators *
function App() {
this.name = 'World';
}
App.annotations = [
new Component({
selector: 'app'
}),
new View({
template:
'<div>\n' +
' <h1>Hello {{ name }}!</h1>\n' +
'</div>\n'
})
];
View
Controller
Directive
Model
Model
Controller
View
Provider
Value
Factory
Constant
Service
DI
Directive
Component
View
Injectable
<<*async>>
<<any>>
@Component({
selector: 'counter'
})
@View({
template: '<input type="text" [value]="num">'
})
class App {
num:number = 0;
constructor() {
setInterval(function() {
this.num++;
}.bind(this), 1000);
}
}
[square brackets]
(round brackets)
@Component({
selector: 'app'
})
@View({
template: `
<button (click)="onClick()">Click me</button>
`
})
class App {
onClick() {
alert('Cool!');
}
}
@Component({
selector: 'app'
})
@View({
template: `
<input id="inp" type="text"
(keyup)="onKeyup($event)" (seven)="onSeven()">
`
})
class App {
onKeyup(event) {
if(event.currentTarget.value.length === 7) {
event.currentTarget.dispatchEvent(new Event('seven'));
}
}
onSeven() {
alert('Cool!');
}
}
(event-binding)="expression"
[property-binding]="expression"
@Directive({
selector: 'input[pass]',
events: ['passMatch'],
hostListeners: {
keyup: 'onKeyup($event.target.value)'
}
})
class PassInput {
passPhrase:string = 'test123';
passMatch:EventEmitter
= new EventEmitter();
onKeyup(value) {
if(value === this.passPhrase) {
this.passMatch.next('matched');
}
}
}
import PassInput from './pass-input.js';
@Component({
selector: 'app'
})
@View({
template: `
<input type="text"
(pass-match)="onPassMatch($event)">
Matched: {{count}}`,
directives: [PassInput]
})
class App {
constructor() { this.count = 0; }
onPassMatch(event) {
this.count++;
}
}
pre-existing injectors
component injectors
element injectors
class ListService {
list:Array<string> = ['One', 'Two', 'Three'];
}
@Component({
selector: 'app',
injectables: [ListService]
})
@View({
template: `List: {{ list }}`
})
class App {
constructor(listService:ListService) {
this.list = listService.list;
}
}
class HelloAbstract {
hello() { throw new Error('Abstract!'); }
}
class HelloConcrete extends HelloAbstract {
hello() { return 'Howdy doodie?'; }
}
@Component({
selector: 'app',
injectables: [
HelloConcrete
]
})
@View({template: '{{ helloService.hello() }}' })
class App {
helloService:HelloAbstract;
constructor(@Inject(HelloConcrete) helloService:HelloAbstract) {
this.helloService = helloService;
}
}
class HelloAbstract {
hello() { throw new Error('Abstract!'); }
}
class HelloConcrete extends HelloAbstract {
hello() { return 'Howdy doodie?'; }
}
@Component({
selector: 'app',
injectables: [
bind(HelloAbstract).toClass(HelloConcrete)
]
})
@View({template: '{{ helloService.hello() }}' })
class App {
helloService:HelloAbstract;
constructor(helloService:HelloAbstract) {
this.helloService = helloService;
}
}
@Directive({
selector: 'button[kamikaze]'
})
class KamikazeButton {
constructor(elem:NgElement) {
elem.domElement.addEventListener('click', function(event) {
event.currentTarget.style.display = 'none';
}.bind(this));
}
}
@Component({ selector: 'app' })
@View({
template: '<button kamikaze>Remove me</button>',
directives: [KamikazeButton]
})
class App {}
@Directive({
selector: '[color-button]',
hostListeners: {click: 'onClick()'}
})
class ColorButton {
constructor(@Parent() panel:ColorPanel,
@Attribute('color-button') color:string) {
this.color = color;
this.panel = panel;
}
onClick() {
this.panel.bgColor(this.color);
}
}
@Directive({ selector: 'color-panel' })
class ColorPanel {
constructor(@PropertySetter('style.background-color') bgColor:Function) {
this.bgColor = bgColor;
}
}