core concepts
slack.jsbelgrade.org
Dušan Stanković
Full-stack developer @ Embroker
@dulerock
me@dulerock.com
Lak za testiranje (karma + jasmine, protractor)
Ekspresivan
Dependency Injection
Directives
Two-way data binding
Built-in stuff (promises($q), ajax($http), jqlite...)
TO BRE!
Performanse (change-detection, template caching...)
Web standardi (ES6, Web components...)
Lak za razumevanje i korišćenje
Model
Directive
DOM
(graph)
Model
Component
DOM
(tree)
Monomorfni vs polimorfni kod
1 klasa po komponenti za change detection
3-10x brže
Immutable
Observable
import {Component, View, bootstrap} from 'angular2/angular2';
@Component({
selector: 'dafed-app'
})
@View({
template: `<h1>Dobrodosli na predavanje {{name}}</h1>`
})
class DafedApp{
name: string;
constructor(){
this.name = "Angular 2.0 - core concepts";
}
}
bootstrap(DafedApp);
Type anotacije
Meta anotacije
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var angular2_1 = require('angular2/angular2');
var DafedApp = (function () {
function DafedApp() {
this.name = "Angular 2.0 - core concepts";
}
DafedApp = __decorate([
angular2_1.Component({
selector: 'dafed-app'
}),
angular2_1.View({
template: "<h1>Dobrodosli na predavanje {{name}}</h1>"
}),
__metadata('design:paramtypes', [])
], DafedApp);
return DafedApp;
})();
angular2_1.bootstrap(DafedApp);
DOM eventi umesto event na scope-u
DI
<predavanja>
<predavanje title="Angular 2.0">...</predavanje>
<predavanje title="ReactJS">...</predavanje>
</predavanja>
@Component({
selector: 'predavanja'
})
@View({
templateUrl: 'views/predavanja.html'
})
class Predavanja {
lista: QueryList<Predavanje>
constructor(@Query(Predavanje) lista:QueryList<Predavanje>) {
this.lista = lista;
}
}
1.x
2.0
Model
View
Controller
Model
View
Controller
Directive
DI: Service, Provider, Factory, Value...
Directive
View
Component
Injectable
import {Component, View, bootstrap} from 'angular2/angular2';
@Component({
selector: 'dafed-prijava'
})
@View({
template: `<h1>Prijavi se za Dafed</h1>
<input type="text" [value]="defaultValue"/>
<button [type]="buttonType">Prijavi se odmah</button>
`
})
export class DafedComponent{
defaultValue: string;
buttonType: string;
constructor(){
this.defaultValue = "Pera Kojot";
this.buttonType = "submit";
}
}
import {Component, View, bootstrap} from 'angular2/angular2';
@Component({
selector: 'dafed-prijava'
})
@View({
template: `<h1>Prijavi se za Dafed</h1>
<button (click)="prijaviSe($event)" (obavesti)="obavestiKorisnika()">
Prijavi se odmah</button>`
})
export class DafedPrijavaComponent{
prijaviSe(event) {
event.currentTarget.dispatchEvent(new Event('obavesti'));
}
obavestiKorisnika(){
alert("Uspesno prijavljen");
}
}
import PassInput from './pass.js';
@Component({
selector: 'dafed-login'
})
@View({
template: `
<input type="password"
(pass-match)="onPassOk($event)">
directives: [PassInput]
})
class DafedLogin {
onPassOk(event) {
alert('pass has 6 chars');
}
}
@Directive({
selector: 'input',
events: ['passMatch'],
hostListeners: {
keyup: 'onKeyup($event.target.value)'
}
})
class PassInput {
passMatch:EventEmitter
= new EventEmitter();
onKeyup(value) {
if(/^[a-zA-Z0-9]{6}$/.test(value)) {
this.passMatch.next('matched');
}
}
}
pre-injectors
component injectors
element injectors
PRODUCTION READY?
@dulerock