SlideShare a Scribd company logo
Angular 2 не так уж
и плох,
а если задуматься то и просто хорош.
Алексей Охрименко ( IPONWEB )
1
Здоровье прежде всего
2
Алексей
Охрименко
Tweeter: @Ai_boy
Gitter: aiboy
3
IPONWEB
4
5
import { Component } from '@angular/core';
@Component({
moduleId: module.id,
selector: 'project-name-app',
template: `
<h1 (click)='onClick()'>
{{title}}
</h1>
`,
styleUrls: ['project-name.component.css']
})
export class PROJECTNAMEAppComponent {
title = 'project-name works!';
}
6
import { Component } from '@angular/core';
@Component({
moduleId: module.id,
selector: 'project-name-app',
template: `
<h1 (click)='onClick()'>
{{title}}
</h1>
`,
styleUrls: ['project-name.component.css']
})
export class PROJECTNAMEAppComponent {
title = 'project-name works!';
}
7
import { Component } from '@angular/core';
@Component({
moduleId: module.id,
selector: 'project-name-app',
template: `
<h1 (click)='onClick()'>
{{title}}
</h1>
`,
styleUrls: ['project-name.component.css']
})
export class PROJECTNAMEAppComponent {
title = 'project-name works!';
}
Глава №1 - И была рука
8
KSS
9
KSS
10
Babel
KSS
11
TypeScript?
KSS
12
Angular 2
Глава №2 - Горы отвращения
13
Angular 2 is Beta*
14
* - now RC1
ASP.Net MVC - Developer Preview 2
15
16
17
([]) [] ()
([]) [] ()
([]) []
([]) [] ()
([]
([]) []
([]) [] ()
([])
18
19
/**
* Simplest possible template in AngularJs-ISH style
*
* @param {String} template - template string
* @param {Object} ctx - template context
* @param {Object} eventHandlerObject - object that will be used as "this" in event handling
* @returns {Node} returns dom node element
*/
export default function angularish(template, ctx, eventHandlerObject) {
var node;
var container = document.createElement('div');
container.innerHTML = template;
var walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, null, false);
while (node = walker.nextNode()) {
// inheritance of context
node.ctx = node.ctx || node.parentNode.ctx || ctx;
// ng-scope allows you to change scope of the node (new scope can be any property of old
scope)
if (node.getAttribute('ng-scope')) {
node.ctx = _getValue(node.ctx, node.getAttribute('ng-scope'));
}
// ng-loop will repeat first child (TODO: reapeat content) and assign correct context
if (node.getAttribute('ng-loop')) {
20
/**
* Simplest possible template in AngularJs-ISH style
*
* @param {String} template - template string
* @param {Object} ctx - template context
* @param {Object} eventHandlerObject - object that will be used as "this" in event handling
* @returns {Node} returns dom node element
*/
export default function angularish(template, ctx, eventHandlerObject) {
var node;
var container = document.createElement('div');
container.innerHTML = template;
var walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, null, false);
while (node = walker.nextNode()) {
// inheritance of context
node.ctx = node.ctx || node.parentNode.ctx || ctx;
// ng-scope allows you to change scope of the node (new scope can be any property of old
scope)
if (node.getAttribute('ng-scope')) {
node.ctx = _getValue(node.ctx, node.getAttribute('ng-scope'));
}
// ng-loop will repeat first child (TODO: reapeat content) and assign correct context
if (node.getAttribute('ng-loop')) {
21
/**
* Simplest possible template in AngularJs-ISH style
*
* @param {String} template - template string
* @param {Object} ctx - template context
* @param {Object} eventHandlerObject - object that will be used as "this" in event handling
* @returns {Node} returns dom node element
*/
export default function angularish(template, ctx, eventHandlerObject) {
var node;
var container = document.createElement('div');
container.innerHTML = template;
var walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, null, false);
while (node = walker.nextNode()) {
// inheritance of context
node.ctx = node.ctx || node.parentNode.ctx || ctx;
// ng-scope allows you to change scope of the node (new scope can be any property of old
scope)
if (node.getAttribute('ng-scope')) {
node.ctx = _getValue(node.ctx, node.getAttribute('ng-scope'));
}
// ng-loop will repeat first child (TODO: reapeat content) and assign correct context
if (node.getAttribute('ng-loop')) {
22
node.value = _getValue(node.ctx, node.getAttribute('ng-value'));
}
// ng-selected will set selected attribute depending on true-finess of value
if (node.getAttribute('ng-selected')) {
var selected = _getValue(node.ctx, node.getAttribute('ng-selected'));
if (selected) {
node.setAttribute('selected', 'yes');
}
}
// ng-text will assign text to node no need for escaping
if (node.getAttribute('ng-text')) {
node.innerText = _getValue(node.ctx, node.getAttribute('ng-text'));
}
// ng-class will simply assign class from defined property
if (node.getAttribute('ng-class')) {
var classVal = _getValue(node.ctx, node.getAttribute('ng-class'));
if (classVal) {
node.className += ' ' + classVal;
}
}
// ng-show shows elements depending on true-finess of the value
if (node.getAttribute('ng-show')) {
23
// ng-scope allows you to change scope of the node (new scope can be any property of old
scope)
if (node.getAttribute('ng-scope')) {
node.ctx = _getValue(node.ctx, node.getAttribute('ng-scope'));
}
// ng-loop will repeat first child (TODO: reapeat content) and assign correct context
if (node.getAttribute('ng-loop')) {
var child = node.children[0];
var array = _getValue(node.ctx, node.getAttribute('ng-loop')) || [];
node.removeChild(child);
array.forEach((item) => {
child = child.cloneNode(true);
child.ctx = item;
node.appendChild(child);
});
}
// ng-value will assign value to node
if (node.getAttribute('ng-value')) {
node.value = _getValue(node.ctx, node.getAttribute('ng-value'));
}
// ng-selected will set selected attribute depending on true-finess of value
if (node.getAttribute('ng-selected')) {
24
// ng-change will add "change" event handler
if (node.getAttribute('ng-change')) {
// closure to rescue
((node)=> {
node.addEventListener('change', (event) => {
eventHandlerObject[node.getAttribute(‘ng-change')]
.bind(eventHandlerObject)(node.ctx, event);
}, true);
})(node);
}
// ng-click will add "click" event handler
if (node.getAttribute('ng-click')) {
// closure to rescue
((node)=> {
node.addEventListener('click', (event) => {
eventHandlerObject[node.getAttribute(‘ng-click')]
.bind(eventHandlerObject)(node.ctx, event);
}, true);
})(node);
}
}
return container;
}
function _getValue(ctx, attrVal) {
if (attrVal === 'self') {
return ctx;
}
25
}
// ng-hide shows elements depending on false-iness of the value
if (node.getAttribute('ng-hide')) {
var isHidden = _getValue(node.ctx, node.getAttribute('ng-hide'));
if (isHidden) {
node.style.display = 'none';
}
}
// ng-change will add "change" event handler
if (node.getAttribute('ng-change')) {
// closure to rescue
((node)=> {
node.addEventListener('change', (event) => {
eventHandlerObject[node.getAttribute(‘ng-change')]
.bind(eventHandlerObject)(node.ctx, event);
}, true);
})(node);
}
// ng-click will add "click" event handler
if (node.getAttribute('ng-click')) {
// closure to rescue
((node)=> {
node.addEventListener('click', (event) => {
eventHandlerObject[node.getAttribute(‘ng-click')]
.bind(eventHandlerObject)(node.ctx, event);
}, true);
})(node);
}
26
[]
()
[()]
27
[property]=‘value’ -> property=‘value’
()
[()]
28
[property]=‘value’ -> property=‘value’
(event)=‘handler()’ -> on-event=‘handler()’
[()]
29
[property]=‘value’ -> property=‘value’
(event)=‘handler()’ -> on-event=‘handler()’
[(target)]=‘value’ -> on-change=‘update()’
-> target=‘value’
30
bind-property=‘value’ -> property=‘value’
(event)=‘handler()’ -> on-event=‘handler()’
[(target)]=‘value’ -> on-change=‘update()’
-> target=‘value’
31
bind-property=‘value’ -> property=‘value’
on-event=‘handler()’ -> on-event=‘handler()’
[(target)]=‘value’ -> on-change=‘update()’
-> target=‘value’
32
bind-property=‘value’ -> property=‘value’
on-event=‘handler()’ -> on-event=‘handler()’
bindon-prop=‘value’ -> on-change=‘update()’
-> target=‘value’
33
<hero-detail *ngIf="currentHero"
[hero]="currentHero"/>
34
<hero-detail template="ngIf:currentHero"
[hero]="currentHero"/>
35
<template [ngIf]="currentHero">
<hero-detail [hero]="currentHero"></hero-detail>
</template>
System.js & JSPM & System.js Builder
36
http://plnkr.co/
System.js & JSPM & System.js Builder
37
<title>angular2 playground</title>
<link rel="stylesheet" href="style.css" />
<script src="https://code.angularjs.org/2.0.0-beta.17/
angular2-polyfills.js"></script>
<script src="https://code.angularjs.org/tools/system.js"></
script>
<script src="https://code.angularjs.org/tools/
typescript.js"></script>
<script src="config.js"></script>
<script>
System.import('app')
.catch(console.error.bind(console));
</script>
</head>
System.js & JSPM & System.js Builder
38
<title>angular2 playground</title>
<link rel="stylesheet" href="style.css" />
<script src="https://code.angularjs.org/2.0.0-beta.17/
angular2-polyfills.js"></script>
<script src="https://code.angularjs.org/tools/system.js"></
script>
<script src="https://code.angularjs.org/tools/
typescript.js"></script>
<script src="config.js"></script>
<script>
System.import('app')
.catch(console.error.bind(console));
</script>
</head>
39
System.config({
//use typescript for compilation
transpiler: 'typescript',
//typescript compiler options
typescriptOptions: {
emitDecoratorMetadata: true
},
//map tells the System loader where to look for things
map: {
app: "./src",
'@angular': 'https://npmcdn.com/@angular',
'rxjs': 'https://npmcdn.com/rxjs@5.0.0-beta.6'
},
//packages defines our app package
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts'
},
'@angular/core': {
main: 'core.umd.js',
defaultExtension: 'js'
},
'@angular/compiler': {
main: 'compiler.umd.js',
defaultExtension: 'js'
},
'@angular/common': {
main: 'common.umd.js',
defaultExtension: 'js'
},
'@angular/platform-browser-dynamic': {
main: 'platform-browser-dynamic.umd.js',
defaultExtension: 'js'
},
'@angular/platform-browser': {
main: 'platform-browser.umd.js',
defaultExtension: 'js'
},
rxjs: {
defaultExtension: 'js'
}
}
});
40
System.config({
//use typescript for compilation
transpiler: 'typescript',
//typescript compiler options
typescriptOptions: {
emitDecoratorMetadata: true
},
//map tells the System loader where to look for things
map: {
app: "./src",
'@angular': 'https://npmcdn.com/@angular',
'rxjs': 'https://npmcdn.com/rxjs@5.0.0-beta.6'
},
//packages defines our app package
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts'
},
'@angular/core': {
main: 'core.umd.js',
defaultExtension: 'js'
},
'@angular/compiler': {
main: 'compiler.umd.js',
defaultExtension: 'js'
},
'@angular/common': {
main: 'common.umd.js',
defaultExtension: 'js'
},
'@angular/platform-browser-dynamic': {
main: 'platform-browser-dynamic.umd.js',
defaultExtension: 'js'
},
'@angular/platform-browser': {
main: 'platform-browser.umd.js',
defaultExtension: 'js'
},
rxjs: {
defaultExtension: 'js'
}
}
});
44 строчки конфига
Не хуже чем Webpack
• Официальный Angular QuickStart репозиторий
• Angular CLI
• Yoman / Slush - генераторы
TypeScript
42
TypeScript
43
TypeScript
44
TypeScript
45
• .Net, Java, Scala background
• SOLID, Design Patterns
• 1.8.10
• Poor documentation - «google search ftw»
Глава №3 - Добыча
46
Размер
47
Development
Production
Size in KB
0 50 100 150 200 250 300 350 400
React Angular 1 Angular 2
Размер - Angular 2 Router
48
Размер - Angular 2 Router
49
Размер - Angular 2 Router
50
CSS
51
import {Component} from '@angular/core'
@Component({
selector: 'my-app',
providers: [],
styles: [`
h2 { color: red; }
`],
template: `
<div>
<h2>Hello {{name}}</h2>
</div>
`,
directives: []
})
export class App {
constructor() {
this.name = 'Angular2 (Release Candidate!)'
}
}
CSS
52
import {Component} from '@angular/core'
@Component({
selector: 'my-app',
providers: [],
styles: [`
body { color: red; }
`],
template: `
<div>
<h2>Hello {{name}}</h2>
</div>
`,
directives: []
})
export class App {
constructor() {
this.name = 'Angular2 (Release Candidate!)'
}
}
CSS
53
Speed - templates
54
55
import { Component } from '@angular/core';
@Component({
moduleId: module.id,
selector: 'project-name-app',
template: `
<h1>
{{title}}
</h1>
`,
styleUrls: ['project-name.component.css']
})
export class PROJECTNAMEAppComponent {
title = 'project-name works!';
}
56
new jit_StaticNodeDebugInfo0([],null,{}),
new jit_StaticNodeDebugInfo0([],null,{}),
new jit_StaticNodeDebugInfo0([],null,{})
]
;
var renderType_PROJECTNAMEAppComponent = null;
function _View_PROJECTNAMEAppComponent0(viewUtils,parentInjector,declarationEl) {
var self = this;
jit_DebugAppView1.call(this,
_View_PROJECTNAMEAppComponent0,renderType_PROJECTNAMEAppComponent,jit_ViewType_COMPONENT2,viewUtils,parentInjec
rationEl,jit_ChangeDetectionStrategy_CheckAlways3,nodeDebugInfos_PROJECTNAMEAppComponent0);
}
_View_PROJECTNAMEAppComponent0.prototype = Object.create(jit_DebugAppView1.prototype);
_View_PROJECTNAMEAppComponent0.prototype.createInternal = function(rootSelector) {
var self = this;
var parentRenderNode = self.renderer.createViewRoot(self.declarationAppElement.nativeElement);
self._el_0 = self.renderer.createElement(parentRenderNode,'h1',self.debug(0,0,0));
self._text_1 = self.renderer.createText(self._el_0,'',self.debug(1,0,4));
self._text_2 = self.renderer.createText(parentRenderNode,'n',self.debug(2,2,5));
self._expr_0 = jit_uninitialized4;
self.init([],[
self._el_0,
self._text_1,
self._text_2
]
,[],[]);
return null;
};
_View_PROJECTNAMEAppComponent0.prototype.detectChangesInternal = function(throwOnChange) {
var self = this;
self.detectContentChildrenChanges(throwOnChange);
self.debug(1,0,4);
57
new jit_StaticNodeDebugInfo0([],null,{}),
new jit_StaticNodeDebugInfo0([],null,{}),
new jit_StaticNodeDebugInfo0([],null,{})
]
;
var renderType_PROJECTNAMEAppComponent = null;
function _View_PROJECTNAMEAppComponent0(viewUtils,parentInjector,declarationEl) {
var self = this;
jit_DebugAppView1.call(this,
_View_PROJECTNAMEAppComponent0,renderType_PROJECTNAMEAppComponent,jit_ViewType_COMPONENT2,viewUtils,parentInjec
rationEl,jit_ChangeDetectionStrategy_CheckAlways3,nodeDebugInfos_PROJECTNAMEAppComponent0);
}
_View_PROJECTNAMEAppComponent0.prototype = Object.create(jit_DebugAppView1.prototype);
_View_PROJECTNAMEAppComponent0.prototype.createInternal = function(rootSelector) {
var self = this;
var parentRenderNode = self.renderer.createViewRoot(self.declarationAppElement.nativeElement);
self._el_0 = self.renderer.createElement(parentRenderNode,'h1',self.debug(0,0,0));
self._text_1 = self.renderer.createText(self._el_0,'',self.debug(1,0,4));
self._text_2 = self.renderer.createText(parentRenderNode,'n',self.debug(2,2,5));
self._expr_0 = jit_uninitialized4;
self.init([],[
self._el_0,
self._text_1,
self._text_2
]
,[],[]);
return null;
};
_View_PROJECTNAMEAppComponent0.prototype.detectChangesInternal = function(throwOnChange) {
var self = this;
self.detectContentChildrenChanges(throwOnChange);
self.debug(1,0,4);
58
self.renderer.createElement
self.renderer.createText
59
Как построить DOM
Роман Дворнов
Speed
immutability
60
import { Component, Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'isOdd' })
export class IsOddPipe implements PipeTransform {
transform(array:any[]) { return array.filter(item => item.isOdd); }
}
@Component({
moduleId: module.id,
selector: 'project-name-app',
pipes: [IsOddPipe],
template: `
<button (click)="add()">add</button>
<div>
<div *ngFor="let item of list | isOdd">
{{ item.name }}
</div>
</div>
`,
styleUrls: ['project-name.component.css']
})
export class PROJECTNAMEAppComponent {
list = []
add() {
this.list.push({ name: ‘test', isOdd: !!(this.list.length % 2)
})
}
}
Speed
immutability
61
import { Component, Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'isOdd' })
export class IsOddPipe implements PipeTransform {
transform(array:any[]) { return array.filter(item => item.isOdd); }
}
@Component({
moduleId: module.id,
selector: 'project-name-app',
pipes: [IsOddPipe],
template: `
<button (click)="add()">add</button>
<div>
<div *ngFor="let item of list | isOdd">
{{ item.name }}
</div>
</div>
`,
styleUrls: ['project-name.component.css']
})
export class PROJECTNAMEAppComponent {
list = []
add() {
this.list.push({ name: ‘test', isOdd: !!(this.list.length % 2)
})
}
}
Speed
immutability
62
import { Component, Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'isOdd' })
export class IsOddPipe implements PipeTransform {
transform(array:any[]) { return array.filter(item => item.isOdd); }
}
@Component({
moduleId: module.id,
selector: 'project-name-app',
pipes: [IsOddPipe],
template: `
<button (click)="add()">add</button>
<div>
<div *ngFor="let item of list | isOdd">
{{ item.name }}
</div>
</div>
`,
styleUrls: ['project-name.component.css']
})
export class PROJECTNAMEAppComponent {
list = []
add() {
this.list.push({ name: ‘test', isOdd: !!(this.list.length % 2)
})
}
}
Speed
immutability
63
import { Component, Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: ‘isOdd’, is_pure: false })
export class IsOddPipe implements PipeTransform {
transform(array:any[]) { return array.filter(item => item.isOdd); }
}
@Component({
moduleId: module.id,
selector: 'project-name-app',
pipes: [IsOddPipe],
template: `
<button (click)="add()">add</button>
<div>
<div *ngFor="let item of list | isOdd">
{{ item.name }}
</div>
</div>
`,
styleUrls: ['project-name.component.css']
})
export class PROJECTNAMEAppComponent {
list = []
add() {
this.list.push({ name: ‘test', isOdd: !!(this.list.length % 2)
})
}
}
Speed
immutability
64
import { Component, Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'isOdd' })
export class IsOddPipe implements PipeTransform {
transform(array:any[]) { return array.filter(item => item.isOdd); }
}
@Component({
moduleId: module.id,
selector: 'project-name-app',
pipes: [IsOddPipe],
template: `
<button (click)="add()">add</button>
<div>
<div *ngFor="let item of list | isOdd">
{{ item.name }}
</div>
</div>
`,
styleUrls: ['project-name.component.css']
})
export class PROJECTNAMEAppComponent {
list = []
add() {
this.list = this.list.splice().filter((i) => i % 2)
})
}
}
Speed - zone.js
65
Zone.fork().run(function () {
zone.inTheZone = true;
setTimeout(function () {
console.log('in the zone: ' + !!zone.inTheZone);
}, 0);
});
console.log('in the zone: ' + !!zone.inTheZone);
—————————————————————————————
'in the zone: false'
'in the zone: true'
Speed - zone.js
66
Zone.fork().run(function () {
zone.inTheZone = true;
setTimeout(function () {
console.log('in the zone: ' + !!zone.inTheZone);
}, 0);
});
console.log('in the zone: ' + !!zone.inTheZone);
—————————————————————————————
'in the zone: false'
'in the zone: true'
TypeScript OOP
67
class GenericService<T> {
items: Array<T> = []
addItem(item: T) {
this.items.push(item)
}
}
interface User {
id: number,
name: string
}
interface Creatives {
type: string,
value: string
}
TypeScript OOP
68
var s = new GenericService<User>();
s.addItem({
id: 1, name: 'asda'
});
s.addItem({
type: ‘asda' // will fail
})
Глава №4 - Первые потери
69
… а вот этого я не ожидал
Потеря почти всей кодовой базы
70
Promise -> RXJS
71
Promise -> RXJS
72
ЗДЕСЬ БЫЛ PROMISE
Promise -> RXJS
73
import {Http, HTTP_PROVIDERS} from 'angular2/http';
@Component({
selector: 'http-app',
viewProviders: [HTTP_PROVIDERS],
templateUrl: 'people.html'
})
class PeopleComponent {
constructor(http: Http) {
http.get('people.json')
.map(res => res.json())
.subscribe(people => this.people = people);
}
}
Promise -> RXJS
74
import {Http, HTTP_PROVIDERS} from 'angular2/http';
@Component({
selector: 'http-app',
viewProviders: [HTTP_PROVIDERS],
templateUrl: 'people.html'
})
class PeopleComponent {
constructor(http: Http) {
http.get('people.json')
.map(res => res.json())
.subscribe(people => this.people = people);
}
}
Promise -> RXJS
75
import {Http, HTTP_PROVIDERS} from 'angular2/http';
@Component({
selector: 'http-app',
viewProviders: [HTTP_PROVIDERS],
templateUrl: 'people.html'
})
class PeopleComponent {
constructor(http: Http) {
http.get('people.json')
.map(res => res.json())
.subscribe(people => this.people = people);
}
}
RXJS
76
RXJS
77
interface IObservable<T>
{
IDisposable Subscribe(IObserver observer);
}
interface IObserver<T>
{
void OnCompleted();
void OnNext(T value);
void OnError(Exception e);
}
ngResources
78
var User = $resource('/user/:userId', {userId:'@id'});
User.get({userId:123}, function(user) {
user.abc = true;
user.$save();
});
ngResources
79
var User = $resource('/user/:userId', {userId:'@id'});
User.get({userId:123}, function(user) {
user.abc = true;
user.$save();
});
Встроенные паттерны канули в небытие!
80
1) component
2) directive
3) filter
4) service
5) provider
6) constant
7) config
8) run
9) module
Встроенные паттерны канули в небытие!
81
1) component
2) template
3) directive
4) route
5) pipe
6) service *
Формы
82
1) [(ngModel)]
Формы
83
1) [(ngModel)]
2) ng-valid | ng-invalid | ng-dirty | ng-pristine | ng-touched | ng-untouched
Формы
84
1) [(ngModel)]
2) ng-valid | ng-invalid | ng-dirty | ng-pristine | ng-touched | ng-untouched
3) FormModel + FormBuilder
Формы
85
1) [(ngModel)]
2) ng-valid | ng-invalid | ng-dirty | ng-pristine | ng-touched | ng-untouched
3) FormModel + FormBuilder
4) Валидация не стала легче
Глава №5 - Happy End
86
Мы уже переехали на Angular 2?
87
НЕТ
88
Почему?
89
1) Потому что Angular 1 не так уж и плох, а если задуматься …
Почему?
90
1) Потому что Angular 1 не так уж и плох, а если задуматься …
2) Потому что React 15 не так уж и плох, а если задуматься …
Почему?
91
1) Потому что Angular 1 не так уж и плох, а если задуматься …
2) Потому что React 15 не так уж и плох, а если задуматься …
3) Потому что Ember не так уж и плох, а если задуматься …
Почему?
92
1) Кодовая база
2) Уровень вхождения
3) Незаконченность*
Почему?
93
1) Кодовая база
2) Уровень вхождения
3) Незаконченность*
Есть ли надежда?
94
Наши шаги
95
1) TypeScript OOP - e2e tests
2) Angular 1.4.x -> 1.5.x
3) AutoNgConverter
О чем мы не поговорили?
96
97
Progressive Web Apps
Native
- Ionic Framework,
- NativeScript
- React Native.
Desktop
- Electron
Universal
- node.js,
- .NET,
- PHP
Dependency Injection
Angular CLI
IDEs
Testing
- patched Karma, Protractor
Animation
Accessibility
Developer Tools
98
-Redux ( ngrx / ng2-redux )
-FLUX
-MV* ( MVC, MVP, MVVM )
-MALEVICH ( COD.js )
Приятного
аппетита!
Tweeter: #Ai_boy
Gitter: aiboy
99
http://bit.ly/1XP0dEh

More Related Content

PDF
ECMA2015 INSIDE
PDF
Angular 2のRenderer
PDF
Proyecto Final Android-SQLite
PDF
Aplicacion turbogenerador java
PDF
Practical JavaScript Programming - Session 3/8
PPTX
es6.concurrency()
PDF
modern javascript, unobtrusive javascript, jquery
ECMA2015 INSIDE
Angular 2のRenderer
Proyecto Final Android-SQLite
Aplicacion turbogenerador java
Practical JavaScript Programming - Session 3/8
es6.concurrency()
modern javascript, unobtrusive javascript, jquery

What's hot (20)

PDF
Proxy & CGLIB
ODP
JavascriptMVC
PDF
Java script.trend(spec)
PDF
SSP - The Simple Singleton Pattern
PDF
HTTP Interceptors com AngularJS
PDF
Android Fast Track CRUD Android PHP MySql
PDF
Aller plus loin avec Doctrine2
PDF
Testování prakticky
ODP
JSF 2 and Ajax
PDF
Practical JavaScript Programming - Session 2/8
PDF
JQuery
PDF
ECMAScript 6 im Produktivbetrieb
DOCX
JAVA Program in NetBeans
PPT
Android Bootcamp Santa Fe GTUG
PPTX
Unit Testing con Jest + Enzime para ReactJs
PDF
Юнит тестирование в Zend Framework 2.0
PDF
Twig, los mejores trucos y técnicas avanzadas
PDF
1- Sourcecode Array
PDF
Einführung in Meteor
PDF
C# Starter L01-Intro and Warm-up
Proxy & CGLIB
JavascriptMVC
Java script.trend(spec)
SSP - The Simple Singleton Pattern
HTTP Interceptors com AngularJS
Android Fast Track CRUD Android PHP MySql
Aller plus loin avec Doctrine2
Testování prakticky
JSF 2 and Ajax
Practical JavaScript Programming - Session 2/8
JQuery
ECMAScript 6 im Produktivbetrieb
JAVA Program in NetBeans
Android Bootcamp Santa Fe GTUG
Unit Testing con Jest + Enzime para ReactJs
Юнит тестирование в Zend Framework 2.0
Twig, los mejores trucos y técnicas avanzadas
1- Sourcecode Array
Einführung in Meteor
C# Starter L01-Intro and Warm-up
Ad

Viewers also liked (20)

PDF
Конструктор / Денис Паясь (Яндекс)
PDF
Vue.js и его брат-близнец Vue-server.js / Андрей Солодовников (НГС)
PDF
React новая эра фронтенд разработки / Роберт Харитонов (Liberty Global)
PPTX
Amazing threesome, rrr... React. Redux. Real world / Ростислав Галкин (Babo)
PDF
"Angular 2: Всех переиграл" Евгений Жарков
PDF
FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6
PDF
Angular2
PDF
Пользовательские свойства как основа архитектуры CSS / Павел Ловцевич (LOVATA)
PPTX
Что делать, когда костыли уже не помогают. Опыт tutu.ru / Роман Грунтович (tu...
PDF
Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)
PDF
UX-дизайнер, ты ли это. Навыки проектировщика в стилизации интерфейсов / Илья...
PDF
Как мы разрабатываем новый фронтенд / Филипп Нехаев (Tinkoff.ru)
PPTX
Стабильность WebGL приложений / Кирилл Дмитренко (Яндекс)
PDF
Классические архитектуры во фронтенде / Александра Шинкевич (LOVATA)
PPTX
Angular vs Angular 2 vs React. Сергей Александров
PDF
Радости и гадости регрессионного тестирования вёрстки / Алексей Малейков (HTM...
PDF
Архитектура поиска в Avito / Андрей Смирнов (Avito)
PDF
Использование Tarantool в качестве платформы виртуализации данных / Константи...
PDF
Чему мы научились, разрабатывая микросервисы / Вадим Мадисон (RuTube)
PDF
FrontDays #1. Алексей Ульянов, React.js и методологии разработки на нём
Конструктор / Денис Паясь (Яндекс)
Vue.js и его брат-близнец Vue-server.js / Андрей Солодовников (НГС)
React новая эра фронтенд разработки / Роберт Харитонов (Liberty Global)
Amazing threesome, rrr... React. Redux. Real world / Ростислав Галкин (Babo)
"Angular 2: Всех переиграл" Евгений Жарков
FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6
Angular2
Пользовательские свойства как основа архитектуры CSS / Павел Ловцевич (LOVATA)
Что делать, когда костыли уже не помогают. Опыт tutu.ru / Роман Грунтович (tu...
Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)
UX-дизайнер, ты ли это. Навыки проектировщика в стилизации интерфейсов / Илья...
Как мы разрабатываем новый фронтенд / Филипп Нехаев (Tinkoff.ru)
Стабильность WebGL приложений / Кирилл Дмитренко (Яндекс)
Классические архитектуры во фронтенде / Александра Шинкевич (LOVATA)
Angular vs Angular 2 vs React. Сергей Александров
Радости и гадости регрессионного тестирования вёрстки / Алексей Малейков (HTM...
Архитектура поиска в Avito / Андрей Смирнов (Avito)
Использование Tarantool в качестве платформы виртуализации данных / Константи...
Чему мы научились, разрабатывая микросервисы / Вадим Мадисон (RuTube)
FrontDays #1. Алексей Ульянов, React.js и методологии разработки на нём
Ad

More from Ontico (20)

PDF
One-cloud — система управления дата-центром в Одноклассниках / Олег Анастасье...
PDF
Масштабируя DNS / Артем Гавриченков (Qrator Labs)
PPTX
Создание BigData-платформы для ФГУП Почта России / Андрей Бащенко (Luxoft)
PDF
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
PDF
Новые технологии репликации данных в PostgreSQL / Александр Алексеев (Postgre...
PDF
PostgreSQL Configuration for Humans / Alvaro Hernandez (OnGres)
PDF
Inexpensive Datamasking for MySQL with ProxySQL — Data Anonymization for Deve...
PDF
Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...
PPTX
ProxySQL Use Case Scenarios / Alkin Tezuysal (Percona)
PPTX
MySQL Replication — Advanced Features / Петр Зайцев (Percona)
PDF
Внутренний open-source. Как разрабатывать мобильное приложение большим количе...
PPTX
Подробно о том, как Causal Consistency реализовано в MongoDB / Михаил Тюленев...
PPTX
Балансировка на скорости проводов. Без ASIC, без ограничений. Решения NFWare ...
PDF
Перехват трафика — мифы и реальность / Евгений Усков (Qrator Labs)
PPT
И тогда наверняка вдруг запляшут облака! / Алексей Сушков (ПЕТЕР-СЕРВИС)
PPTX
Как мы заставили Druid работать в Одноклассниках / Юрий Невиницин (OK.RU)
PPTX
Разгоняем ASP.NET Core / Илья Вербицкий (WebStoating s.r.o.)
PPTX
100500 способов кэширования в Oracle Database или как достичь максимальной ск...
PPTX
Apache Ignite Persistence: зачем Persistence для In-Memory, и как он работает...
PDF
Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...
One-cloud — система управления дата-центром в Одноклассниках / Олег Анастасье...
Масштабируя DNS / Артем Гавриченков (Qrator Labs)
Создание BigData-платформы для ФГУП Почта России / Андрей Бащенко (Luxoft)
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
Новые технологии репликации данных в PostgreSQL / Александр Алексеев (Postgre...
PostgreSQL Configuration for Humans / Alvaro Hernandez (OnGres)
Inexpensive Datamasking for MySQL with ProxySQL — Data Anonymization for Deve...
Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...
ProxySQL Use Case Scenarios / Alkin Tezuysal (Percona)
MySQL Replication — Advanced Features / Петр Зайцев (Percona)
Внутренний open-source. Как разрабатывать мобильное приложение большим количе...
Подробно о том, как Causal Consistency реализовано в MongoDB / Михаил Тюленев...
Балансировка на скорости проводов. Без ASIC, без ограничений. Решения NFWare ...
Перехват трафика — мифы и реальность / Евгений Усков (Qrator Labs)
И тогда наверняка вдруг запляшут облака! / Алексей Сушков (ПЕТЕР-СЕРВИС)
Как мы заставили Druid работать в Одноклассниках / Юрий Невиницин (OK.RU)
Разгоняем ASP.NET Core / Илья Вербицкий (WebStoating s.r.o.)
100500 способов кэширования в Oracle Database или как достичь максимальной ск...
Apache Ignite Persistence: зачем Persistence для In-Memory, и как он работает...
Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...

Angular 2 не так уж и плох... А если задуматься, то и просто хорош / Алексей Охрименко (IPONWEB)

  • 1. Angular 2 не так уж и плох, а если задуматься то и просто хорош. Алексей Охрименко ( IPONWEB ) 1
  • 5. 5 import { Component } from '@angular/core'; @Component({ moduleId: module.id, selector: 'project-name-app', template: ` <h1 (click)='onClick()'> {{title}} </h1> `, styleUrls: ['project-name.component.css'] }) export class PROJECTNAMEAppComponent { title = 'project-name works!'; }
  • 6. 6 import { Component } from '@angular/core'; @Component({ moduleId: module.id, selector: 'project-name-app', template: ` <h1 (click)='onClick()'> {{title}} </h1> `, styleUrls: ['project-name.component.css'] }) export class PROJECTNAMEAppComponent { title = 'project-name works!'; }
  • 7. 7 import { Component } from '@angular/core'; @Component({ moduleId: module.id, selector: 'project-name-app', template: ` <h1 (click)='onClick()'> {{title}} </h1> `, styleUrls: ['project-name.component.css'] }) export class PROJECTNAMEAppComponent { title = 'project-name works!'; }
  • 8. Глава №1 - И была рука 8
  • 13. Глава №2 - Горы отвращения 13
  • 14. Angular 2 is Beta* 14 * - now RC1
  • 15. ASP.Net MVC - Developer Preview 2 15
  • 16. 16
  • 17. 17 ([]) [] () ([]) [] () ([]) [] ([]) [] () ([] ([]) [] ([]) [] () ([])
  • 18. 18
  • 19. 19 /** * Simplest possible template in AngularJs-ISH style * * @param {String} template - template string * @param {Object} ctx - template context * @param {Object} eventHandlerObject - object that will be used as "this" in event handling * @returns {Node} returns dom node element */ export default function angularish(template, ctx, eventHandlerObject) { var node; var container = document.createElement('div'); container.innerHTML = template; var walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, null, false); while (node = walker.nextNode()) { // inheritance of context node.ctx = node.ctx || node.parentNode.ctx || ctx; // ng-scope allows you to change scope of the node (new scope can be any property of old scope) if (node.getAttribute('ng-scope')) { node.ctx = _getValue(node.ctx, node.getAttribute('ng-scope')); } // ng-loop will repeat first child (TODO: reapeat content) and assign correct context if (node.getAttribute('ng-loop')) {
  • 20. 20 /** * Simplest possible template in AngularJs-ISH style * * @param {String} template - template string * @param {Object} ctx - template context * @param {Object} eventHandlerObject - object that will be used as "this" in event handling * @returns {Node} returns dom node element */ export default function angularish(template, ctx, eventHandlerObject) { var node; var container = document.createElement('div'); container.innerHTML = template; var walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, null, false); while (node = walker.nextNode()) { // inheritance of context node.ctx = node.ctx || node.parentNode.ctx || ctx; // ng-scope allows you to change scope of the node (new scope can be any property of old scope) if (node.getAttribute('ng-scope')) { node.ctx = _getValue(node.ctx, node.getAttribute('ng-scope')); } // ng-loop will repeat first child (TODO: reapeat content) and assign correct context if (node.getAttribute('ng-loop')) {
  • 21. 21 /** * Simplest possible template in AngularJs-ISH style * * @param {String} template - template string * @param {Object} ctx - template context * @param {Object} eventHandlerObject - object that will be used as "this" in event handling * @returns {Node} returns dom node element */ export default function angularish(template, ctx, eventHandlerObject) { var node; var container = document.createElement('div'); container.innerHTML = template; var walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, null, false); while (node = walker.nextNode()) { // inheritance of context node.ctx = node.ctx || node.parentNode.ctx || ctx; // ng-scope allows you to change scope of the node (new scope can be any property of old scope) if (node.getAttribute('ng-scope')) { node.ctx = _getValue(node.ctx, node.getAttribute('ng-scope')); } // ng-loop will repeat first child (TODO: reapeat content) and assign correct context if (node.getAttribute('ng-loop')) {
  • 22. 22 node.value = _getValue(node.ctx, node.getAttribute('ng-value')); } // ng-selected will set selected attribute depending on true-finess of value if (node.getAttribute('ng-selected')) { var selected = _getValue(node.ctx, node.getAttribute('ng-selected')); if (selected) { node.setAttribute('selected', 'yes'); } } // ng-text will assign text to node no need for escaping if (node.getAttribute('ng-text')) { node.innerText = _getValue(node.ctx, node.getAttribute('ng-text')); } // ng-class will simply assign class from defined property if (node.getAttribute('ng-class')) { var classVal = _getValue(node.ctx, node.getAttribute('ng-class')); if (classVal) { node.className += ' ' + classVal; } } // ng-show shows elements depending on true-finess of the value if (node.getAttribute('ng-show')) {
  • 23. 23 // ng-scope allows you to change scope of the node (new scope can be any property of old scope) if (node.getAttribute('ng-scope')) { node.ctx = _getValue(node.ctx, node.getAttribute('ng-scope')); } // ng-loop will repeat first child (TODO: reapeat content) and assign correct context if (node.getAttribute('ng-loop')) { var child = node.children[0]; var array = _getValue(node.ctx, node.getAttribute('ng-loop')) || []; node.removeChild(child); array.forEach((item) => { child = child.cloneNode(true); child.ctx = item; node.appendChild(child); }); } // ng-value will assign value to node if (node.getAttribute('ng-value')) { node.value = _getValue(node.ctx, node.getAttribute('ng-value')); } // ng-selected will set selected attribute depending on true-finess of value if (node.getAttribute('ng-selected')) {
  • 24. 24 // ng-change will add "change" event handler if (node.getAttribute('ng-change')) { // closure to rescue ((node)=> { node.addEventListener('change', (event) => { eventHandlerObject[node.getAttribute(‘ng-change')] .bind(eventHandlerObject)(node.ctx, event); }, true); })(node); } // ng-click will add "click" event handler if (node.getAttribute('ng-click')) { // closure to rescue ((node)=> { node.addEventListener('click', (event) => { eventHandlerObject[node.getAttribute(‘ng-click')] .bind(eventHandlerObject)(node.ctx, event); }, true); })(node); } } return container; } function _getValue(ctx, attrVal) { if (attrVal === 'self') { return ctx; }
  • 25. 25 } // ng-hide shows elements depending on false-iness of the value if (node.getAttribute('ng-hide')) { var isHidden = _getValue(node.ctx, node.getAttribute('ng-hide')); if (isHidden) { node.style.display = 'none'; } } // ng-change will add "change" event handler if (node.getAttribute('ng-change')) { // closure to rescue ((node)=> { node.addEventListener('change', (event) => { eventHandlerObject[node.getAttribute(‘ng-change')] .bind(eventHandlerObject)(node.ctx, event); }, true); })(node); } // ng-click will add "click" event handler if (node.getAttribute('ng-click')) { // closure to rescue ((node)=> { node.addEventListener('click', (event) => { eventHandlerObject[node.getAttribute(‘ng-click')] .bind(eventHandlerObject)(node.ctx, event); }, true); })(node); }
  • 29. 29 [property]=‘value’ -> property=‘value’ (event)=‘handler()’ -> on-event=‘handler()’ [(target)]=‘value’ -> on-change=‘update()’ -> target=‘value’
  • 30. 30 bind-property=‘value’ -> property=‘value’ (event)=‘handler()’ -> on-event=‘handler()’ [(target)]=‘value’ -> on-change=‘update()’ -> target=‘value’
  • 31. 31 bind-property=‘value’ -> property=‘value’ on-event=‘handler()’ -> on-event=‘handler()’ [(target)]=‘value’ -> on-change=‘update()’ -> target=‘value’
  • 32. 32 bind-property=‘value’ -> property=‘value’ on-event=‘handler()’ -> on-event=‘handler()’ bindon-prop=‘value’ -> on-change=‘update()’ -> target=‘value’
  • 36. System.js & JSPM & System.js Builder 36 http://plnkr.co/
  • 37. System.js & JSPM & System.js Builder 37 <title>angular2 playground</title> <link rel="stylesheet" href="style.css" /> <script src="https://code.angularjs.org/2.0.0-beta.17/ angular2-polyfills.js"></script> <script src="https://code.angularjs.org/tools/system.js"></ script> <script src="https://code.angularjs.org/tools/ typescript.js"></script> <script src="config.js"></script> <script> System.import('app') .catch(console.error.bind(console)); </script> </head>
  • 38. System.js & JSPM & System.js Builder 38 <title>angular2 playground</title> <link rel="stylesheet" href="style.css" /> <script src="https://code.angularjs.org/2.0.0-beta.17/ angular2-polyfills.js"></script> <script src="https://code.angularjs.org/tools/system.js"></ script> <script src="https://code.angularjs.org/tools/ typescript.js"></script> <script src="config.js"></script> <script> System.import('app') .catch(console.error.bind(console)); </script> </head>
  • 39. 39 System.config({ //use typescript for compilation transpiler: 'typescript', //typescript compiler options typescriptOptions: { emitDecoratorMetadata: true }, //map tells the System loader where to look for things map: { app: "./src", '@angular': 'https://npmcdn.com/@angular', 'rxjs': 'https://npmcdn.com/[email protected]' }, //packages defines our app package packages: { app: { main: './main.ts', defaultExtension: 'ts' }, '@angular/core': { main: 'core.umd.js', defaultExtension: 'js' }, '@angular/compiler': { main: 'compiler.umd.js', defaultExtension: 'js' }, '@angular/common': { main: 'common.umd.js', defaultExtension: 'js' }, '@angular/platform-browser-dynamic': { main: 'platform-browser-dynamic.umd.js', defaultExtension: 'js' }, '@angular/platform-browser': { main: 'platform-browser.umd.js', defaultExtension: 'js' }, rxjs: { defaultExtension: 'js' } } });
  • 40. 40 System.config({ //use typescript for compilation transpiler: 'typescript', //typescript compiler options typescriptOptions: { emitDecoratorMetadata: true }, //map tells the System loader where to look for things map: { app: "./src", '@angular': 'https://npmcdn.com/@angular', 'rxjs': 'https://npmcdn.com/[email protected]' }, //packages defines our app package packages: { app: { main: './main.ts', defaultExtension: 'ts' }, '@angular/core': { main: 'core.umd.js', defaultExtension: 'js' }, '@angular/compiler': { main: 'compiler.umd.js', defaultExtension: 'js' }, '@angular/common': { main: 'common.umd.js', defaultExtension: 'js' }, '@angular/platform-browser-dynamic': { main: 'platform-browser-dynamic.umd.js', defaultExtension: 'js' }, '@angular/platform-browser': { main: 'platform-browser.umd.js', defaultExtension: 'js' }, rxjs: { defaultExtension: 'js' } } }); 44 строчки конфига
  • 41. Не хуже чем Webpack • Официальный Angular QuickStart репозиторий • Angular CLI • Yoman / Slush - генераторы
  • 45. TypeScript 45 • .Net, Java, Scala background • SOLID, Design Patterns • 1.8.10 • Poor documentation - «google search ftw»
  • 46. Глава №3 - Добыча 46
  • 47. Размер 47 Development Production Size in KB 0 50 100 150 200 250 300 350 400 React Angular 1 Angular 2
  • 48. Размер - Angular 2 Router 48
  • 49. Размер - Angular 2 Router 49
  • 50. Размер - Angular 2 Router 50
  • 51. CSS 51 import {Component} from '@angular/core' @Component({ selector: 'my-app', providers: [], styles: [` h2 { color: red; } `], template: ` <div> <h2>Hello {{name}}</h2> </div> `, directives: [] }) export class App { constructor() { this.name = 'Angular2 (Release Candidate!)' } }
  • 52. CSS 52 import {Component} from '@angular/core' @Component({ selector: 'my-app', providers: [], styles: [` body { color: red; } `], template: ` <div> <h2>Hello {{name}}</h2> </div> `, directives: [] }) export class App { constructor() { this.name = 'Angular2 (Release Candidate!)' } }
  • 55. 55 import { Component } from '@angular/core'; @Component({ moduleId: module.id, selector: 'project-name-app', template: ` <h1> {{title}} </h1> `, styleUrls: ['project-name.component.css'] }) export class PROJECTNAMEAppComponent { title = 'project-name works!'; }
  • 56. 56 new jit_StaticNodeDebugInfo0([],null,{}), new jit_StaticNodeDebugInfo0([],null,{}), new jit_StaticNodeDebugInfo0([],null,{}) ] ; var renderType_PROJECTNAMEAppComponent = null; function _View_PROJECTNAMEAppComponent0(viewUtils,parentInjector,declarationEl) { var self = this; jit_DebugAppView1.call(this, _View_PROJECTNAMEAppComponent0,renderType_PROJECTNAMEAppComponent,jit_ViewType_COMPONENT2,viewUtils,parentInjec rationEl,jit_ChangeDetectionStrategy_CheckAlways3,nodeDebugInfos_PROJECTNAMEAppComponent0); } _View_PROJECTNAMEAppComponent0.prototype = Object.create(jit_DebugAppView1.prototype); _View_PROJECTNAMEAppComponent0.prototype.createInternal = function(rootSelector) { var self = this; var parentRenderNode = self.renderer.createViewRoot(self.declarationAppElement.nativeElement); self._el_0 = self.renderer.createElement(parentRenderNode,'h1',self.debug(0,0,0)); self._text_1 = self.renderer.createText(self._el_0,'',self.debug(1,0,4)); self._text_2 = self.renderer.createText(parentRenderNode,'n',self.debug(2,2,5)); self._expr_0 = jit_uninitialized4; self.init([],[ self._el_0, self._text_1, self._text_2 ] ,[],[]); return null; }; _View_PROJECTNAMEAppComponent0.prototype.detectChangesInternal = function(throwOnChange) { var self = this; self.detectContentChildrenChanges(throwOnChange); self.debug(1,0,4);
  • 57. 57 new jit_StaticNodeDebugInfo0([],null,{}), new jit_StaticNodeDebugInfo0([],null,{}), new jit_StaticNodeDebugInfo0([],null,{}) ] ; var renderType_PROJECTNAMEAppComponent = null; function _View_PROJECTNAMEAppComponent0(viewUtils,parentInjector,declarationEl) { var self = this; jit_DebugAppView1.call(this, _View_PROJECTNAMEAppComponent0,renderType_PROJECTNAMEAppComponent,jit_ViewType_COMPONENT2,viewUtils,parentInjec rationEl,jit_ChangeDetectionStrategy_CheckAlways3,nodeDebugInfos_PROJECTNAMEAppComponent0); } _View_PROJECTNAMEAppComponent0.prototype = Object.create(jit_DebugAppView1.prototype); _View_PROJECTNAMEAppComponent0.prototype.createInternal = function(rootSelector) { var self = this; var parentRenderNode = self.renderer.createViewRoot(self.declarationAppElement.nativeElement); self._el_0 = self.renderer.createElement(parentRenderNode,'h1',self.debug(0,0,0)); self._text_1 = self.renderer.createText(self._el_0,'',self.debug(1,0,4)); self._text_2 = self.renderer.createText(parentRenderNode,'n',self.debug(2,2,5)); self._expr_0 = jit_uninitialized4; self.init([],[ self._el_0, self._text_1, self._text_2 ] ,[],[]); return null; }; _View_PROJECTNAMEAppComponent0.prototype.detectChangesInternal = function(throwOnChange) { var self = this; self.detectContentChildrenChanges(throwOnChange); self.debug(1,0,4);
  • 60. Speed immutability 60 import { Component, Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'isOdd' }) export class IsOddPipe implements PipeTransform { transform(array:any[]) { return array.filter(item => item.isOdd); } } @Component({ moduleId: module.id, selector: 'project-name-app', pipes: [IsOddPipe], template: ` <button (click)="add()">add</button> <div> <div *ngFor="let item of list | isOdd"> {{ item.name }} </div> </div> `, styleUrls: ['project-name.component.css'] }) export class PROJECTNAMEAppComponent { list = [] add() { this.list.push({ name: ‘test', isOdd: !!(this.list.length % 2) }) } }
  • 61. Speed immutability 61 import { Component, Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'isOdd' }) export class IsOddPipe implements PipeTransform { transform(array:any[]) { return array.filter(item => item.isOdd); } } @Component({ moduleId: module.id, selector: 'project-name-app', pipes: [IsOddPipe], template: ` <button (click)="add()">add</button> <div> <div *ngFor="let item of list | isOdd"> {{ item.name }} </div> </div> `, styleUrls: ['project-name.component.css'] }) export class PROJECTNAMEAppComponent { list = [] add() { this.list.push({ name: ‘test', isOdd: !!(this.list.length % 2) }) } }
  • 62. Speed immutability 62 import { Component, Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'isOdd' }) export class IsOddPipe implements PipeTransform { transform(array:any[]) { return array.filter(item => item.isOdd); } } @Component({ moduleId: module.id, selector: 'project-name-app', pipes: [IsOddPipe], template: ` <button (click)="add()">add</button> <div> <div *ngFor="let item of list | isOdd"> {{ item.name }} </div> </div> `, styleUrls: ['project-name.component.css'] }) export class PROJECTNAMEAppComponent { list = [] add() { this.list.push({ name: ‘test', isOdd: !!(this.list.length % 2) }) } }
  • 63. Speed immutability 63 import { Component, Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: ‘isOdd’, is_pure: false }) export class IsOddPipe implements PipeTransform { transform(array:any[]) { return array.filter(item => item.isOdd); } } @Component({ moduleId: module.id, selector: 'project-name-app', pipes: [IsOddPipe], template: ` <button (click)="add()">add</button> <div> <div *ngFor="let item of list | isOdd"> {{ item.name }} </div> </div> `, styleUrls: ['project-name.component.css'] }) export class PROJECTNAMEAppComponent { list = [] add() { this.list.push({ name: ‘test', isOdd: !!(this.list.length % 2) }) } }
  • 64. Speed immutability 64 import { Component, Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'isOdd' }) export class IsOddPipe implements PipeTransform { transform(array:any[]) { return array.filter(item => item.isOdd); } } @Component({ moduleId: module.id, selector: 'project-name-app', pipes: [IsOddPipe], template: ` <button (click)="add()">add</button> <div> <div *ngFor="let item of list | isOdd"> {{ item.name }} </div> </div> `, styleUrls: ['project-name.component.css'] }) export class PROJECTNAMEAppComponent { list = [] add() { this.list = this.list.splice().filter((i) => i % 2) }) } }
  • 65. Speed - zone.js 65 Zone.fork().run(function () { zone.inTheZone = true; setTimeout(function () { console.log('in the zone: ' + !!zone.inTheZone); }, 0); }); console.log('in the zone: ' + !!zone.inTheZone); ————————————————————————————— 'in the zone: false' 'in the zone: true'
  • 66. Speed - zone.js 66 Zone.fork().run(function () { zone.inTheZone = true; setTimeout(function () { console.log('in the zone: ' + !!zone.inTheZone); }, 0); }); console.log('in the zone: ' + !!zone.inTheZone); ————————————————————————————— 'in the zone: false' 'in the zone: true'
  • 67. TypeScript OOP 67 class GenericService<T> { items: Array<T> = [] addItem(item: T) { this.items.push(item) } } interface User { id: number, name: string } interface Creatives { type: string, value: string }
  • 68. TypeScript OOP 68 var s = new GenericService<User>(); s.addItem({ id: 1, name: 'asda' }); s.addItem({ type: ‘asda' // will fail })
  • 69. Глава №4 - Первые потери 69 … а вот этого я не ожидал
  • 70. Потеря почти всей кодовой базы 70
  • 73. Promise -> RXJS 73 import {Http, HTTP_PROVIDERS} from 'angular2/http'; @Component({ selector: 'http-app', viewProviders: [HTTP_PROVIDERS], templateUrl: 'people.html' }) class PeopleComponent { constructor(http: Http) { http.get('people.json') .map(res => res.json()) .subscribe(people => this.people = people); } }
  • 74. Promise -> RXJS 74 import {Http, HTTP_PROVIDERS} from 'angular2/http'; @Component({ selector: 'http-app', viewProviders: [HTTP_PROVIDERS], templateUrl: 'people.html' }) class PeopleComponent { constructor(http: Http) { http.get('people.json') .map(res => res.json()) .subscribe(people => this.people = people); } }
  • 75. Promise -> RXJS 75 import {Http, HTTP_PROVIDERS} from 'angular2/http'; @Component({ selector: 'http-app', viewProviders: [HTTP_PROVIDERS], templateUrl: 'people.html' }) class PeopleComponent { constructor(http: Http) { http.get('people.json') .map(res => res.json()) .subscribe(people => this.people = people); } }
  • 77. RXJS 77 interface IObservable<T> { IDisposable Subscribe(IObserver observer); } interface IObserver<T> { void OnCompleted(); void OnNext(T value); void OnError(Exception e); }
  • 78. ngResources 78 var User = $resource('/user/:userId', {userId:'@id'}); User.get({userId:123}, function(user) { user.abc = true; user.$save(); });
  • 79. ngResources 79 var User = $resource('/user/:userId', {userId:'@id'}); User.get({userId:123}, function(user) { user.abc = true; user.$save(); });
  • 80. Встроенные паттерны канули в небытие! 80 1) component 2) directive 3) filter 4) service 5) provider 6) constant 7) config 8) run 9) module
  • 81. Встроенные паттерны канули в небытие! 81 1) component 2) template 3) directive 4) route 5) pipe 6) service *
  • 83. Формы 83 1) [(ngModel)] 2) ng-valid | ng-invalid | ng-dirty | ng-pristine | ng-touched | ng-untouched
  • 84. Формы 84 1) [(ngModel)] 2) ng-valid | ng-invalid | ng-dirty | ng-pristine | ng-touched | ng-untouched 3) FormModel + FormBuilder
  • 85. Формы 85 1) [(ngModel)] 2) ng-valid | ng-invalid | ng-dirty | ng-pristine | ng-touched | ng-untouched 3) FormModel + FormBuilder 4) Валидация не стала легче
  • 86. Глава №5 - Happy End 86
  • 87. Мы уже переехали на Angular 2? 87
  • 89. Почему? 89 1) Потому что Angular 1 не так уж и плох, а если задуматься …
  • 90. Почему? 90 1) Потому что Angular 1 не так уж и плох, а если задуматься … 2) Потому что React 15 не так уж и плох, а если задуматься …
  • 91. Почему? 91 1) Потому что Angular 1 не так уж и плох, а если задуматься … 2) Потому что React 15 не так уж и плох, а если задуматься … 3) Потому что Ember не так уж и плох, а если задуматься …
  • 92. Почему? 92 1) Кодовая база 2) Уровень вхождения 3) Незаконченность*
  • 93. Почему? 93 1) Кодовая база 2) Уровень вхождения 3) Незаконченность*
  • 95. Наши шаги 95 1) TypeScript OOP - e2e tests 2) Angular 1.4.x -> 1.5.x 3) AutoNgConverter
  • 96. О чем мы не поговорили? 96
  • 97. 97 Progressive Web Apps Native - Ionic Framework, - NativeScript - React Native. Desktop - Electron Universal - node.js, - .NET, - PHP Dependency Injection Angular CLI IDEs Testing - patched Karma, Protractor Animation Accessibility Developer Tools
  • 98. 98 -Redux ( ngrx / ng2-redux ) -FLUX -MV* ( MVC, MVP, MVVM ) -MALEVICH ( COD.js )