Angular2 Michał PrzyszczypkowskiAngular2 By Michał Przyszczypkowski
Background revolution instead of evolution currently in BETA (since December 2015) release date not yet announced Angular2 By Michał Przyszczypkowski
Typescript Superset of JS (ES6) Compiles to plain JS Supported in all major IDE's
function greet(name: string):string { return "Hello, " + name; } let greeting: string = greet("Mike"); Strongly typed
class Student { public fullname : string; private age: number; private dontKnowWhatWillBeThere:any; constructor(public firstname:string, public lastname:string) { //... } } Classes & interfaces
class Student { public fullname : string; private age: number; private dontKnowWhatWillBeThere:any; constructor(public firstname:string, public lastname:string) { //... } } Classes & interfaces class Student { lastname: string; fullname : string; constructor(firstname:string, lastname:string) { this.firstname = firstname; this.lastname = lastname; } }
interface Person { firstname: string; lastname: string; } Classes & interfaces
interface Person { firstname: string; lastname: string; } Classes & interfaces function greeter(person : Person) { return "Hello, " + person.firstname + " " + person.lastname; } let user: Person = new Student("Mike", "Someone");
interface Person { firstname: string; lastname: string; } Classes & interfaces function greeter(person : Person) { return "Hello, " + person.firstname + " " + person.lastname; } let user: Person = new Student("Mike", "Someone"); let user: Person = {firstname: 'Mike', lastname: 'Snow'}
Annotations / Decorators Decorators are proposed as standard for ES Already implemented in TS
Annotations / Decorators @ExampleAnnotation({ annotationKey: annotationValue }) export class ExampleClass { } Decorators are proposed as standard for ES Already implemented in TS
Annotations / Decorators @ExampleAnnotation({ annotationKey: annotationValue }) export class ExampleClass { } Decorators are proposed as standard for ES Already implemented in TS @AnotherExampleAnnotation({ annotationKey: annotationValue }) doSomething() { //... }
Modules export interface Person { name: string; } export class PeopleService { getPeople(): People[] { return [{name: 'Mike'}]; } } export const value:string = 'Something';
Modules import * as library from "./module"; import { Person, PeopleService } from "./module"; console.log(library.value); let peopleSrv = new PeopleService(); let people: Person[] = peopleSrv.getPeople(); export interface Person { name: string; } export class PeopleService { getPeople(): People[] { return [{name: 'Mike'}]; } } export const value:string = 'Something';
Angular2 App is made of components
Angular2 App is made of components Tree structure
Angular2 App is made of components Tree structure Concepts from AngularJS 1.x no longer relevant
Angular2 App is made of components Tree structure Concepts from AngularJS 1.x no longer relevant $scope, $directive, $controller, $service, $factory - no longer exist
Angular2 There is no $scope.$apply() No need to use $timeout, $interval etc. All events that may lead to bindings changes are patched within library We don't need to handle changes detection anymore
Components @Component({ selector: 'click-me', templateUrl: 'template.html' }) export class ClickMeComponent { private label: string = 'Click there!'; onClickMe(){ alert('Hello.'); } }
Components @Component({ selector: 'click-me', templateUrl: 'template.html' }) export class ClickMeComponent { private label: string = 'Click there!'; onClickMe(){ alert('Hello.'); } } properties methods component config
Components @Component({ selector: 'click-me', templateUrl: 'template.html' }) export class ClickMeComponent { private label: string = 'Click there!'; onClickMe(){ alert('Hello.'); } } <body> <click-me></click-me> </body> properties methods component config
Selectors @Component({ selector: 'click-me' ... }) <click-me></click-me>
Selectors @Component({ selector: 'click-me' ... }) <click-me></click-me> @Component({ selector: '[click-me]' ... }) <div click-me=""></div>
Inputs @Component({ selector: 'click-me', templateUrl: 'template.html', inputs: ['message'] }) export class ClickMeComponent { private message: string; onClickMe(){ alert(this.message); } }
Inputs @Component({ selector: 'click-me', templateUrl: 'template.html', inputs: ['message'] }) export class ClickMeComponent { private message: string; onClickMe(){ alert(this.message); } } <click-me message="Peekaboo"></click-me>
Outputs @Component({ selector: 'click-me', templateUrl: 'template.html', outputs: ['onClicked'] }) export class ClickMeComponent { private onClicked: EventEmitter<string> = new EventEmitter<string>(); onClickMe(){ this.onClicked.emit("Hello"); } }
Outputs @Component({ selector: 'click-me', templateUrl: 'template.html', outputs: ['onClicked'] }) export class ClickMeComponent { private onClicked: EventEmitter<string> = new EventEmitter<string>(); onClickMe(){ this.onClicked.emit("Hello"); } } <body> <click-me (onClicked)="doSomething($event)"></click-me> </body>
Styles @Component({ selector: 'click-me', templateUrl: 'template.html', styles: [`.click-btn { color: red; }`] }) export class ClickMeComponent { ... }
Styles @Component({ selector: 'click-me', templateUrl: 'template.html', styles: [`.click-btn { color: red; }`] }) export class ClickMeComponent { ... } @Component({ selector: 'click-me', templateUrl: 'template.html', styles: [`.click-btn { color: red; }`], encapsulation: ViewEncapsulation.None // Native / Emulated }) export class ClickMeComponent { ... }
Directives @Directive({ selector: '[click-me]', styles: [`.click-btn { color: red; }`] }) export class ClickMeDirective { ... }
Template language @Component({ selector: 'click-me', templateUrl: 'template.html' }) export class ClickMeComponent { private label: string = 'Click there!'; onClickMe(){ alert('Hello.'); } }
Template language @Component({ selector: 'click-me', templateUrl: 'template.html' }) export class ClickMeComponent { private label: string = 'Click there!'; onClickMe(){ alert('Hello.'); } } <button (click)="onClickMe()">{{ label }}</button>
Template language <click-me message="Peekaboo"></click-me>
Template language <click-me message="Peekaboo"></click-me> <click-me [message]="peekabooVariable"></click-me>
Template language <click-me message="Peekaboo"></click-me> <click-me [message]="peekabooVariable"></click-me> <click-me [message]="peekabooVariable" (onClicked)="doSth($event)"></click-me>
Structural directives <span *ngFor="#item of items"> {{ item.name }} </span>
Structural directives <span *ngFor="#item of items; #index = index"> item no {{ index }} </span> <span *ngFor="#item of items"> {{ item.name }} </span>
Structural directives <span *ngFor="#item of items; #index = index"> item no {{ index }} </span> <span *ngFor="#item of items"> {{ item.name }} </span> explicit declaration
Structural directives <span *ngFor="#item of items; #index = index"> item no {{ index }} </span> <span *ngFor="#item of items"> {{ item.name }} </span> <span *ngIf="isVisible"> conditional item </span> explicit declaration
Build-in directives <span [class.blue]="isBlue"> TEXT </span>
Build-in directives <span [class.blue]="isBlue"> TEXT </span> <span [style.backgroundColor]="colorVariable"> TEXT </span>
Build-in directives <span [class.blue]="isBlue"> TEXT </span> <span [style.backgroundColor]="colorVariable"> TEXT </span> <span [style.display]="isHidden ? 'none' : 'block'"> TEXT </span>
Build-in directives <span [class.blue]="isBlue"> TEXT </span> <span [style.backgroundColor]="colorVariable"> TEXT </span> <span [hidden]="isHidden"> TEXT </span> <span [style.display]="isHidden ? 'none' : 'block'"> TEXT </span>
Build-in directives <span [class.blue]="isBlue"> TEXT </span> <span [style.backgroundColor]="colorVariable"> TEXT </span> <span [hidden]="isHidden"> TEXT </span> <span (click)="onClick()" (mouseenter)="onMouseEnter()"> TEXT </span> <span [style.display]="isHidden ? 'none' : 'block'"> TEXT </span>
Transclusion <example-component> <h1>Inner title</h1> <span>Inner text</span> </example-component>
Transclusion <div class="example-component-template"> <h1>Outer title</h1> <ng-content></ng-content> </div> <example-component> <h1>Inner title</h1> <span>Inner text</span> </example-component> content will go there
Transclusion <div class="example-component-template"> <h1>Outer title</h1> <ng-content></ng-content> </div> <example-component> <h1>Inner title</h1> <span>Inner text</span> </example-component> <div class="example-component-template"> <h1>Outer title</h1> <h1>Inner title</h1> <span>Inner text</span> </div> content will go there
Services class ItemsRepository { private items: Product[]; getItems(): Products[] { return this.items; } }
class ItemsRepository { private items: Product[]; getItems(): Products[] { return this.items; } } import {ItemsRepository} from '../itemsRepo' @Component({ selector: 'click-me', templateUrl: 'template.html', providers: [ItemsRepository] }) export class ItemList { private items: Product[]; constructor(repo: ItemsRepository) { this.items = repo.getItems(); } } Dependency Injection
class ItemsRepository { private items: Product[]; getItems(): Products[] { return this.items; } } import {ItemsRepository} from '../itemsRepo' @Component({ selector: 'click-me', templateUrl: 'template.html', providers: [ItemsRepository] }) export class ItemList { private items: Product[]; constructor(repo: ItemsRepository) { this.items = repo.getItems(); } } Dependency Injection first import
class ItemsRepository { private items: Product[]; getItems(): Products[] { return this.items; } } import {ItemsRepository} from '../itemsRepo' @Component({ selector: 'click-me', templateUrl: 'template.html', providers: [ItemsRepository] }) export class ItemList { private items: Product[]; constructor(repo: ItemsRepository) { this.items = repo.getItems(); } } Dependency Injection first import set as provider
class ItemsRepository { private items: Product[]; getItems(): Products[] { return this.items; } } import {ItemsRepository} from '../itemsRepo' @Component({ selector: 'click-me', templateUrl: 'template.html', providers: [ItemsRepository] }) export class ItemList { private items: Product[]; constructor(repo: ItemsRepository) { this.items = repo.getItems(); } } Dependency Injection first import set as provider inject in constructor
App ItemsEdition ItemsList C D E Providers visibility
App ItemsEdition ItemsList C D E providers: [ItemsRepository] Providers visibility
App ItemsEdition ItemsList C D E providers: [ItemsRepository] Whole app share the same instance of ItemsRepository service Providers visibility
App ItemsEdition ItemsList C D E
App ItemsEdition ItemsList C D E providers: [ItemsRepository] providers: [ItemsRepository]
App ItemsEdition ItemsList C D E providers: [ItemsRepository] providers: [ItemsRepository] Each subtree has its own instance of service.
class Api { loadItems(): Products[] { return this.items; } } DI between services import {Api} from "./api"; @Injectable() class ItemsRepository { constructor(private api:Api) { } getItems(): Products[] { this.api.loadItems(); } }
Mocking providers import {FakeItemsRepository} from '../fakeItemsRepo' @Component({ selector: 'click-me', templateUrl: 'template.html', providers: [ provide(ItemsRepository, {useClass: FakeItemsRepository}) ] }) export class ItemList { // ... }
Mocking providers import {FakeItemsRepository} from '../fakeItemsRepo' @Component({ selector: 'click-me', templateUrl: 'template.html', providers: [ provide(ItemsRepository, {useClass: FakeItemsRepository}) ] }) export class ItemList { // ... } use custom provider
Routing
Routing routes point to components
Routing routes point to components @RouteConfig([ {path: '/', component: Home, as: 'Home'}, {path: '/list', component: Items, as: 'List'} ]} @Component({..}) class ...
Routing routes point to components @RouteConfig([ {path: '/', component: Home, as: 'Home'}, {path: '/list', component: Items, as: 'List'} ]} @Component({..}) class ... <router-outlet></router-outlet>
Routing parameters @RouteConfig([ {path: '/item/:id', component: Item, as: 'Item'} ]}
Routing parameters @RouteConfig([ {path: '/item/:id', component: Item, as: 'Item'} ]} constructor(params:RouteParams) { let routeParamValue:string = params.get('id'); }
Nested routes
Nested routes
Nested routes <router-outlet>
Nested routes <router-outlet>
Nested routes <router-outlet> <router-outlet>
Nested routes <router-outlet> <router-outlet> <router-outlet>
Nested routes @RouteConfig([ {path: '/home', component: Home, as: 'Home'}, {path: '/items/...', component: Items, as: 'List'} ]} @Component({..}) class ... <router-outlet></router-outlet>
Nested routes @RouteConfig([ {path: '/home', component: Home, as: 'Home'}, {path: '/items/...', component: Items, as: 'List'} ]} @Component({..}) class ... <router-outlet></router-outlet> @RouteConfig([ {path: '/add', component: AddItem, as: 'Add'}, {path: '/edit/:id', component: EditItem, as: 'Edit'} ]} @Component({..}) class ... <router-outlet></router-outlet>
Nested routes /home /items/add /items/edit/1 Home Items ItemsAddItem EditItem
Navigation <a [routerLink]="['Home']">Home</a>
Navigation <a [routerLink]="['Home']">Home</a> let router:Router; router.navigate(['Home']);
Navigation <a [routerLink]="['Home']">Home</a> let router:Router; router.navigate(['Home']); <a [routerLink]="['Items', 'Add']">Home</a>
Navigation <a [routerLink]="['Home']">Home</a> let router:Router; router.navigate(['Home']); <a [routerLink]="['Items', 'Add']">Home</a> <a [routerLink]="['Items', 'Edit', {id: 99}]">Home</a>
Navigation <a [routerLink]="['Home']">Home</a> let router:Router; router.navigate(['Home']); <a [routerLink]="['Items', 'Add']">Home</a> <a [routerLink]="['Items', 'Edit', {id: 99}]">Home</a> <a [routerLink]="['Item', {id:99}, 'Edit']">Home</a> /item/:id/edit
Lifecycle hooks
Lifecycle hooks @Component({...}) export class ComponentClass implements OnInit, OnDestroy { ngOnInit():any { ... } ngOnDestroy():any { ... } } How to hook?
Component lifecycle hooks OnInit OnDestroy DoCheck OnChanges AfterContentInit AfterContentChecked AfterViewInit AfterViewChecked
Router lifecycle hooks CanActivate OnActivate CanDeactivate OnDeactivate OnReuse
https://angular.io/docs/ts/latest/guide/ http://blog.thoughtram.io/ Resources
Thank you. Questions?

An introduction to Angular2