Technozaure - Angular2

68
Angular 2 @EmmanuelDemey

Transcript of Technozaure - Angular2

Angular 2@EmmanuelDemey

Emmanuel

DEMEYConsultant & Formateur Web

Zenika Nord

@EmmanuelDemey

Web / Domotique / Histoire / Biérologie

Les choses que nous n'aimons pas...

Architecture AngularJS

MV* MV* MV*

Architecture AngularJS

MV* MV* MV*

Architecture AngularJS

DI (provider, service, factory...)

MV* MV* MV*

Architecture AngularJS

DI (provider, service, factory...)

MV* MV* MV*

Filtres

Architecture AngularJS

DI (provider, service, factory...)

MV* MV* MV*

Filtres

API des Directivesapp.directive('MyDirective', function(){ return { restrict: 'AE', require: '?^^ngModel', scope: { variable: '@' }, compile: function(...) { return { pre: function(...) { ... }, post: function(...) { ... } } }, link: function(...) { ... } }});

app.directive('MyDirective', function(){ return { restrict: 'AE', require: '?^^ngModel', scope: { variable: '@' }, compile: function(...) { return { pre: function(...) { ... }, post: function(...) { ... } } }, link: function(...) { ... } }});

API des Directives

app.directive('MyDirective', function(){ return { restrict: 'AE', require: '?^^ngModel', scope: { variable: '@' }, compile: function(...) { return { pre: function(...) { ... }, post: function(...) { ... } } }, link: function(...) { ... } }});

API des Directives

app.directive('MyDirective', function(){ return { restrict: 'AE', require: '?^^ngModel', scope: { variable: '@' }, compile: function(...) { return { pre: function(...) { ... }, post: function(...) { ... } } }, link: function(...) { ... } }});

API des Directives

<input ng-model="firstName">

<p> {{firstName }}</p>

2-way data-binding

<input ng-model="firstName" ng-model-options="options"><p> {{firstName }}</p>

2-way data-binding

<input ng-model="firstName">

<p> {{::firstName }}</p>

2-way data-binding

Et ce n'est pas fini...

Mais aussi...

Pas de Server-Side Rendering

Gestion des événements (ngClick, ...)

Gestion des attributs HTML (ngSrc, ...)

La solution... Angular 2

Attention !

Version Alpha

P(eu|as) de Doc

Architecture

Composants

Injection de Dépendance

Pipes

Architecture Angular 2

<app></app>

Architecture Angular 2

<app></app>

menu grid

gallery

Architecture Angular 2

<app></app>

menu grid

gallery

DI

(classes ES6 ou TypeScript)

Pipes

(classes ES6 ou TypeScript)

La Famille JavaScript

La Famille JavaScript

ES5

La Famille JavaScript

ES5

ES2015

La Famille JavaScript

ES5

ES2015

La Famille JavaScript

ES5

ES2015

TypeScript

Les Web Components

Custom Elements Templates Imports Shadow DOM

Composants Angular 2

Ressources de base en Angular 2

Tout est composant

Application représentée par un arbre

de composants

Utilisation de métadonnées pour

configurer un composant

//<my-app></my-app>function MyAppComponent() {

}

MyAppComponent.annotations = [ new angular.ComponentAnnotation({ selector: 'my-app' }), new angular.ViewAnnotation({ template: "<main>" + "<h1> This is my first Angular2 app</h1>" + "</main>" })];

Composant version ES5

import {Component, View} from 'angular2/angular2';

@Component({selector: 'my-app'})@View({ template: `<main> <h1> This is my first Angular2 app</h1> </main>`})class MyAppComponent {

}

Composant version TypeScript

import {Component, View, bootstrap} from 'angular2/angular2';@Component({selector: 'my-app'})@View({ template: `<main> <h1> This is my first Angular2 app</h1> </main>`})class MyAppComponent {

}bootstrap(MyAppComponent);

Bootstrap de l'Application

Binding

Root Cpt

Child1 Cpt Child2 Cpt

[property]="expression"(event)="update()"

Property Binding

<input [attr]="expression" />

Accès à toutes les propriétés des éléments

HTML

Possibilité de définir de nouvelles propriétés

Compatibilité avec d'autres spécifications

Property Binding

<body> <h1>My First Angular2 app</h1></body>

Property Binding

<body> <h1 [textContent]="'My First Angular2 app'"> </h1></body>

Property Binding

<body> <h1>{{'My First Angular2 app'}} </h1></body>

Property Binding//<beerItem [beer]="'Maredsous'"></beerItem>@Component({ selector: 'beerItem', properties: ['beer']})@View({ template: `<section> <h2>{{beer}}</h2> <button>Je veux celle-ci !</button> </section>`})class BeerItem{ beer: String;

}

Event Binding

<input (event)="expression" />

Accès à tous les événements des éléments

HTML

Possibilité de définir de nouveaux événements

Event Bindings//<beerItem [beer]="'Maredsous'" (selectBeer)="sendToBeerTap()"></beerItem>@Component({ selector: 'beerItem', properties: ['beer'], events: ['selectBeer']})@View({ template: `<section> <h2>{{beer}}</h2> <button (click)="selectItem()">Je veux celle-ci !</button> </section>`})class BeerItem { beer: String; selectBeer: EventEmitter; selectItem() { this.selectBeer.next(this.beer); }}

Syntaxe valide ?

“ Attribute names must consist of one or

more characters other than the space

characters, U+0000 NULL, """, "'", ">", "/",

"=", the control characters, and any

characters that are not defined by Unicode.

Syntaxe valide ?

Syntaxe valide ?

Component Dependency

Nécessité d'importer les composants

nécessaires à votre application

Propriété directives de @View

Component Dependencyimport {Component, View, bootstrap, NgFor} from 'angular2/angular2';import {BeerItem} from 'BeerItem';

@Component({ selector: 'my-app'})@View({ template: `<main class="mdl-layout__content"> <ul class="googleapp-card-list"> <li *ng-for="#beer of beers"> <beerItem [beer]="beer"></beerItem> </li> </ul> </main>`, directives: [NgFor, BeerItem]})class MyAppComponent { public beers: String[] = []; constructor() { }}

Injection de Dépendances

Code métier dans des services

Chaque Service est un singleton

Principe d'Hollywood

Multiples implémentations en NG1 !

Injection de Dépendances

app.service('TapService', function($http){ this.getBeer = function(beerId){ return $http.get('/api/i-am-thirsty/' + beerId); };});

app.controller('AppCtrl', function(TapService){ this.selectBeer = function(idBeer){ return TapService.getBeer(idBeer); }});

DI version Angular2

1 Injecteur principal + 1 Injecteur par composant

Hérite de l'injecteur parent

Possibilité de redéfinir le Service à injecter

Utilisation d'annotations en ES6 et des types en

TypeScript

Services disponibles via le constructeur du

composant

Injecteur Principal - toValue

@Component({selector: 'my-app'})@View({ template: `<main> <h1> Welcome to our {{breweryName}}</h1> </main>`})class MyAppComponent { constructeur(public breweryName:String){ }}

bootstrap(MyAppComponent, [bind(String).toValue('Zenika Brewery')]);

Injecteur Principal - toClass

@Component({selector: 'my-app'})@View({ template: `<main> <h1> Welcome to our {{breweryName}}</h1> </main>`})class MyAppComponent { constructeur(private breweryService:BreweryService){ this.breweryName = this.breweryService.getBreweryName(); }}

bootstrap(MyAppComponent, [bind(BreweryService).toClass(BreweryService)]);

Injecteur Principal - toClass@Component({selector: 'my-app'})@View({ template: `<main> <h1> Welcome to our {{breweryName}}</h1> </main>`})class MyAppComponent { constructeur(private breweryService:BreweryService){ this.breweryName = this.breweryService.getBreweryName(); }}

bootstrap(MyAppComponent, [BreweryService]);

Injecteur Principal -

toFactory@Component({selector: 'my-app'})@View({ template: `<main> <h1> Welcome to our {{breweryName}}</h1> </main>`})class MyAppComponent { constructeur(public breweryName:String){ }}

bootstrap(MyAppComponent, [bind(String) .toFactory((BreweryService) => { return BreweryService.getBreweryName(); }, [BreweryService])]);

Child Injector

@Component({selector: 'my-app'})@View({ template: `<main> <welcome-message></welcome-message> </main>`, directives: [WelcomeMessage]})class MyAppComponent { constructeur(public breweryName:String){ }}

bootstrap(MyAppComponent, [bind(String).toValue('Zenika Brewery')]);

Child Injector

@Component({ selector: 'welcome-message'})@View({ template: `<h1>Welcome to our {{breweryName}}</h1>`})class WelcomeMessage{ constructeur(public breweryName:String){ }}

Child Injector

@Component({ selector: 'welcome-message'})@View({ template: `<h1>Welcome to our {{breweryName}}</h1>`, bindings: [ bind(String).toValue('Awesome Zenika Brewery') ]})class WelcomeMessage{ constructeur(public breweryName:String){ }}

Pipes

Identiques aux filtres d'AngularJS 1

Permet de manipuler une donnée

Utilisation d'une classe annotée @Pipe

Pipes disponibles dans le framework :

upperCase, lowerCase, Async,

Number, limitTo, json et date

Pipes

import {Pipe} from 'angular2/angular2';

@Pipe({ name: 'UpperCasePipe'})export class UpperCasePipe implements PipeTransform { transform(value: String, args: any[]) { return value.toUpperCase(); }}

Pipes

import {Component, View} from 'angular2/angular2';import {UpperCasePipe} from './UpperCasePipe.ts'

@Component({ selector: 'comp'})@View({ template: `<div>{{'Démo utilisant les pipes' | UpperCasePipe}}</div>`, pipes: [UpperCasePipe]})export class Component{}

Pipesimport {Component, View} from 'angular2/angular2';import {UpperCasePipe} from './UpperCasePipe.ts'

@Component({ selector: 'comp'})@View({ template: ``, bindings: [UpperCasePipe] })export class Component{ constructor(public upperCasePipe:UpperCasePipe){ this.upperCasePipe.transform('Un autre exemple...'); }}

@Component

@View@Directive

@View

@Animation

@Inject

@InjectLazy

@Optional

@Host

@Parent

@Pipe

@Property

@Event

@RouteConfig

@HostBinding

@HostEvent

@ContentChild

@ContentChildren

@ViewChildren

Roadmap

Questions ?