angular 2 par cyril balit & douglas duteil
TRANSCRIPT
READY FOR ANGULAR 2 ?
@cbalit @douglasduteil
Angular 2 est encore en Alpha, ainsi la syntaxe présentée ici est sujet à être changée et | ou simplifiée
Disclaimer
Il était une fois un framework...
Angular
Créé par Miško Hevery et Adam AbronswPremière version le 30 juin 2011 (2009)Version actuelle 1.4.6 (17 septembre 2015)
Des milliers d’applications en production:
https://www.madewithangular.com/
https://github.com/angular/angular.js/wiki/Projects-using-AngularJS
Frameworks MVC mais
Architecture
Les ressources
■ angular-ui (composants boostrap , router…)■ restangular■ angular-strap■ angular translate■ ng-table■ angular-file-upload
OK
■ Productivité■ Orienté Tests (l’injection de dépendances et les modules)■ Orienté service (découplage)■ Les templates en HTML■ Communauté
KO
■ Dirty checking (boite noire)■ Performance■ Pas de rendering coté serveur : SEO :(■ Syntaxe parfois éxotique (Services, directives…)■ L’annonce de la version 2.0
La communication
Ng-Europe le 23 octobre 2014
L’incertitude
“On va pas le coder en Angular c’est mort votre truc”- M. X -
Ok on recommence...
● Maintenance de la 1.X (2018)● Ng-conf le 5 mars 2015● Migration progressive (new Router, ng-upgrade)● Adoption de TypeScript et partenariat avec Microsoft
source : http://angularjs.blogspot.fr/2015/08/angular-1-and-angular-2-coexistence.html
Perspectives
■ Reboot complet■ Supprime
■ les scopes■ les controlleurs■ DDO■ Modules
Les objectifs
■ mobile first■ Performance■ TypeScript■ Simplicité■ Standards: ES6, Web components■ ...
ref: https://angular.io/features.html
Les performances
“Today, Angular2 is 5x faster than Angular 1” Misko, 02/10/15
Deep Tree Benchmark 2015-02-09
Go...
Librairies tiers
■ System.js■ universel (ES6
module, AMD, Common..)
■ importe notre application
■ es6-shim.js■ transpile to ES5
<!DOCTYPE html>
<html>
<head>
<script src="es6-shim.js"></script>
<script src="system.js"></script>
<script src="angular2.dev.js"></script>
</head>
<body>
<my-app></my-app>
<script>
System.import('app');
</script>
</body>
</html>
Le langage
■ Typescript■ ES6■ types■ annotations
■ Javascript■ ES6■ ES5
@Component({ selector: 'my-app'
})
@View({
template: '<h1 id="output">My First Angular 2 App</h1>'
})
class AppComponent { }
var AppComponent = ng.Component({
selector: 'my-app'
})
.View({
template: '<h1 id="output">My First Angular 2 App</h1>'
})
.Class({
constructor: function () { }
});
Démarrage de notre application
■ Import■ Définition d’un composant ■ boostrap
import {Component, View, bootstrap} from 'angular2/angular2';
@Component({
selector: 'my-app'
})
@View({
template: '<h1 id="output">My First Angular 2 App</h1>'
})
class AppComponent { }
bootstrap(AppComponent);
Les composants
Simplification
Plus de controller, de scope… mais 2 types de composants:
■ Qui ajoutent un comportement au DOM: les directives■ Qui encapsulent une vue: les components■ Les service seront de simples classes
Un composant
■ Une classe ■ utilise la syntaxe de
classe ES6■ implémentation du
composant■ Ce que verra la vue
class AppComponent {
name:string;
constructor(){
this.name='Cyril';
}
}
Un composant
■ les annotations ■ component pour
associer une composant à un sélecteur
■ view pour indiquer comment le composant s’affiche
@Component({
selector: 'my-app'
})
@View({
template: '<h1 id="output">My First Angular 2 App</h1>'
})
class AppComponent {
name:string;
constructor(){
this.name='Cyril';
}
}
Un composant
■ importer les dépendances
import {Component, View} from 'angular2/angular2';
@Component({
selector: 'my-app'
})
@View({
template: '<h1 id="output">My First Angular 2 App</h1>'
})
class AppComponent {
name:string;
constructor(){
this.name='Cyril';
}
}
Simplification : les directives
Plus de scope isolé, de restriction, de transclusion, de compile/link….
Une directive
■ Annotation dédiéeimport {Directive} from 'angular2/angular2';
@Directive({
})
export class MyDirective {
}
Une directive : plus de restrict
■ invocations possibles : un selecteur
■ element-name: pour restreindre à un élément
■ [attribute]: pour restreindre à un attribut
■ .class: pour restreindre à une classe
■ [attribute=value]: restreint à un attribut avec une certaine valeur
■ :not(sub_selector): si l’élément ne match pas le sous-sélecteur
import {Directive} from 'angular2/angular2';
@Directive({
selector: '[my-directive]'})
export class MyDirective {
}
Une directive : plus de scope isolé
■ Properties■ Paires de key-value■ directiveProperty/bindi
ngProperty
import {Directive} from 'angular2/angular2';
@Directive({
selector: '[my-directive]',
properties: [directiveProperty: bindingProp],})
export class MyDirective {
}
Une directive
■ Event■ Propager des
évènements custom■ écoute des
événements sur l’host
import {Directive} from 'angular2/angular2';
@Directive({
selector: '[my-directive]',
properties: [directiveProperty: bindingProp],
hostListeners: {'click':'onClick($event)'}})
export class MyDirective {
somethingChange: EventEmitter;
constructor(){
this.somethingChange = new EventEmitter();
}
onClick($event) {
this.somethingChange.next({$event, data});
}
}
Une directive
■ Pour l’utiliser■ l’importer: plus de
collision de noms■ déclarer la directive
dans l’annotation View■ L’utiliser dans le
template
import {Component, View} from 'angular2/angular2';
import {MyDirective} from 'path/to/MyDirective';
@Component({
...
})
@View({
directives: [MyDirective],
template: '<h1 my-directive></h1>'
})
class AppComponent {
...
}
Un service
■ Une simple classe■ On récupère le service par
injection de dépendanceimport {MyService} from 'path/to/MyService';
@Component({
...
})
@View({
...
})
class AppComponent {
constructor(@Inject(MyService) myService) {
myService.myMethod();
}
}
export class MyService {
myMethod() {}
}
Le template
Simplification : templating
Properties, events et références
3 types de binding
Event et properties:
■ Lisibilité■ Event et propriété sont l’API public d’un
composant■ parent -> enfant : property binding■ enfant -> parent : event binding■ Mixe des 2 pour du two-way bindings:
[(ng-model)]
[Property] (Event)
CHILD
PARENT
Templating avancé
■ Importer les diectives■ Les déclarer■ Dans le template
import {CORE_DIRECTIVES} from 'angular2/angular2';
@View({
directives: [CORE_DIRECTIVES],
})
class AppComponent {
fruits:[{name:’apple’},{name:’banana’}];
}
<ul>
<li *ng-for="#fruit of fruits; #i=index">
{{ i }} : {{ fruit.name }}
</li>
</ul>
<div *ng-if="isAdmin">Edit</div>
Pipes: Transformer de la donnée
■ Pipes natifs■ currency■ date■ lowercase, uppercase■ limitTo■ asynch■ json■ decimal■ percent
■ Pipe custom
import {Pipe} from 'angular2/angular2';
@Pipe({
name: ‘mypipe’,
})
class MyPipe {
transform(value,args){
…
return newValue;
}
}
<div>{{data | mypipe:arg1:arg2}}</div>
Routes
Boostrap
Récupérer les dépendances du Router et les intégrer dans notre injecteur
import {ROUTER_PROVIDERS, bootstrap} from 'angular2/angular2';
import {App} from 'ts/app/app';
bootstrap(App,[ROUTER_PROVIDERS]);
Configuration
■ RouterConfig■ path: l’url associée■ as: alias pour la route
utilisé pour référencer les routes dans le HTML
■ component: nom du composant à associer à la route
import {RouteConfig, Router} from 'angular2/router'
@View({
directives:[ROUTER_DIRECTIVES]
})
@RouteConfig([
{ path: '/first, as: 'FirstComponent', component: FirstComponent},
])
export class App {
...
}
Paramètres
■ Dans le path après ‘:’■ accessibles via RouteParams injecté dans le composant
@RouteConfig([
{ path: '/second/edit/:id', as: 'SecondComponent', component: SecondComponent}
])
class App {
constructor(@Inject(RouteParams) routeParams) {
this.id = routeParams.get('id');}
Directives
■ router-link■ router-outlet
<a [router-link]="['/firstComponent']">FirstComponent</a><a [router-link]="['/SecondComponent',{id:obj.id}]">SecondComponent</a>
<section class="container"> <router-outlet></router-outlet></section>
L’injection de dépendances
Angular 1
■ Identifié par un nom■ Que des singletons■ Toujours synchrones■ Collision de noms■ Intrinsèque au framework
myModuleApp.factory("CountService", function (dep1, dep2, ...) {
return {
increment : function(){
}
};
});
function myController($scope, CountService){
CountService.increment();
};
Le principe
■ L’injector expose l’API pour créer des instances de dépendances■ Le Provider indique à l’injector comment créer la dépendance■ La dépendance est le type d’objet à créer
Récupérer une dépendance
■ Singleton■ Pour avoir des instances
■ Utiliser une factory■ Créer un injector fils
import { Injector } from 'angular2/di';
var injector = Injector.resolveAndCreate([
Car,
Engine,
Tires,
Doors
]);
var car = injector.get(Car);
Le provider
■ Fait le lien entre un TOKEN et une FACTORY
■ Permet de découpler dépendance et implémentation
■ API pour:■ binder à une simple
valeur:■ faire des alias de token■ créer des factory
provide(String, {useValue: 'Hello World'})
provide(Engine, {useClass: Engine})provide(V8, {useExisting: Engine})
provide(Engine, {useFactory: () => {
return function () {
if (IS_V8) {
return new V8Engine();
} else {
return new V6Engine();
}
}
}})
Injector fils
■ crée avec Injector.createAndResolveChild()
■ Au niveau de chaque composant
■ Ces instances seront alors différentes
■ Remontent la chaîne pour résoudre les dépendances
Alors ?
■ Orientation composant■ Simplification■ Typescript, ES6■ Stabilisation API/concepts (universalité)■ Préparer la transition
http://angularjs.blogspot.fr/2015/08/angular-1-and-angular-2-coexistence.htmlhttp://blog.thoughtram.io/angular/2015/10/24/upgrading-apps-to-angular-2-using-ngupgrade.html
■ Application complexes ?
Ressources
● Site Officiel : https://angular.io/● API : https://angular.io/docs/js/latest/api/● Thoughtram Blog : http://blog.thoughtram.io/categories/angular-2/● Overview: http://angular-tips.com/blog/2015/06/why-will-angular-2-rock/
Merci ! @cbalit@douglasduteil