Upload
demey-emmanuel
View
943
Download
1
Embed Size (px)
Citation preview
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
Les composants
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
Erreur si composants non utilisés
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() { ... }}
Support des
WebComponents
WebComponents
@Component({ })@View({ template: string, templateUrl: string, encapsulation?: ViewEncapsulation, directives?: List<any>, styles?: List<string>, styleUrls?: List<string>,})class BeerItem { }
WebComponents//From modules/angular2/src/core/render/api.ts
/** * How the template and styles of a view should be encapsulated. */export enum ViewEncapsulation { /** * Emulate scoping of styles by preprocessing the style rules * and adding additional attributes to elements. This is the default. */ Emulated, /** * Uses the native mechanism of the renderer. For the DOM this means creating a * ShadowRoot. */ Native, /** * Don't scope the template nor the styles. */ None}
Injection de Dépendance
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(private 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
Petit Rappel
{{ collectionOfBeers | orderBy:'note' | limitTo:5 }}
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, PipeTransform} 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: 'widget1'})@View({ template: `<div>{{'Démo utilisant les pipes' | UpperCasePipe}}</div>`, pipes: [UpperCasePipe]})export class Widget1{}
Pipesimport {Component, View} from 'angular2/angular2';import {UpperCasePipe} from './UpperCasePipe.ts'
@Component({ selector: 'widget1'})@View({ template: ``, bindings: [UpperCasePipe] })export class Widget1{ 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
Pour une migration heureuse...
John Papa's
styleguide
Autres Règles
1 composant AngularJS par fichier
ECMAScript 2015
Syntaxe Component As
bindToController dans l'API des
directives
Component-First Approach
Utilise le nouveau Router
Création de service via la méthode
service
eslint-plugin-angular
npm install --save-dev eslint eslint-plugin-angular
Implémente le guideline de John Papa
Rules :
Component-First Approach : ng_no_controller
controllerAs : ng_controller_as_*
ngUpgrade.jsMixer AngularJS et
Angular2
Démo
https://github.com/Gillespie59/
angular2-migration-sample
Repository Github
Documentation
http://blog.thoughtram.io/
NG Europe 2014
NG Conf 2015
AngularU
ESLint Plugin Angular
John Papa Styleguide
Questions ?