XebiConFr 15 - Brace yourselves Angular 2 is coming
-
Upload
xebia-france -
Category
Technology
-
view
876 -
download
1
Transcript of XebiConFr 15 - Brace yourselves Angular 2 is coming
Brace yourselves ANGULAR 2
is coming
Alexandre Hebert @dijxdream Dmytro Podyachiy @dimapod79
#XebiConFr
PRÉSENTATEURS
Dmytro Podyachiy@dimapod79
Alexandre Hebert @dijxdream
#XebiConFr
TOUR D’HORIZON
#XebiConFr
● Natif : ↗ performances● Expressif : ↘ boilerplate ↗ productivité● Orienté mobile : ↗ expérience utilisateur● Orienté composant : ↗ modularité
MOTIVATIONS
“The Changing Web”, V. Georgiev
#XebiConFr
APPROCHE WEB COMPONENT
Respect des nouveaux standards du Web
#XebiConFr
● AtScript ?● TypeScript ?● EcmaScript 5, 6 ?● CoffeeScript ?
ANGULAR 2, ENKOIKÇÉKODÉ ?
#XebiConFr
TYPESCRIPT
#XebiConFr
● TypeScript avec décorateurs● ES 6 avec annotations
ANGULAR 2, ENKOIKONKODE ?
NB : Traceur + SystemJs = Mandatory
● ES 5 avec beaucoup de courage
#XebiConFr
✓ Navigateurs modernes≈ IE 9 supporté (avec Polyfills)
ANGULAR 2, OUÇÉKÇAMARCHE ?
#XebiConFr
✗ BYE BYE
QUID D’IE 7 & 8 ?
#XebiConFr
BREAKING CHANGES
#XebiConFr
THE FIRST ANGULAR 2 EFFECT
#XebiConFr
● Two-way data binding● Controllers● Scope, Root scope● $watch, $observe, $apply● Digest cycles● angular.module(...● ...
IL ÉTAIT UNE FOIS ANGULAR 1...
#XebiConFr
● ng-repeat● ng-model● ng-class● ng-if● ...
ET LES DIRECTIVES ?
#XebiConFr
ET LES DIRECTIVES ?
Enfin presq
ue...
#XebiConFr
FINAL ANGULAR 2 EFFECT
#XebiConFr
$ ./MIGRATION NG 1>&2 ?
#XebiConFr
● ✗ Controllers / ✓ Directives (et attributs ‘&’)● Éviter l’usage de $scope : controllerAs● Privilégier les services● Utiliser ‘angular.component’ (NG 1.5)
et…Basculer en TypeScript
ANTICIPATION
#XebiConFr
● Intégrer NG2 avec l’existant
● Adopter un approche opportuniste :○ Si modification directive => component○ Modifier les services associés
● Utiliser NG1.5 et le shortcut “.component()”
COHABITATION
#XebiConFr
Pas de miracles...
MIGRATION
#XebiConFr
PRODUCTION READY?
#XebiConFr
● Nouvelle version / 15 jours● Maturité des navigateurs● Pas de Release Candidate
PAS ENCORE !
Version courante : alpha.37 Developer Preview
#XebiConFr
GET /ANGULAR/2/RELEASEDATE
Très bientôt - Fin 2015
#XebiConFr
COMPONENTSPierre angulaire de l’application Angular 2
#XebiConFr
ARBORESCENCE DES COMPOSANTS
#XebiConFr
@COMPONENT
@Component({ selector: 'my-component'})class MyComponent {
}
<div> <my-component></my-component></div>
Decorator
Utilisation
#XebiConFr
@VIEW (1/3)
@Component({ selector: 'my-component'})@View({ template: "<span>Hello {{message}}!</span>"})class MyComponent {
message:string; constructor() { this.message = 'World'; }}
Inline
#XebiConFr
@VIEW (2/3)
@Component({ selector: 'my-component'})@View({ template: ` <span> Hello {{message}} ! </span> `})class MyComponent {
message:string; constructor() { this.message = 'World'; }}
Inline multi-ligne
#XebiConFr
@VIEW (3/3)
@Component({ selector: 'my-component'})@View({ templateUrl: 'cmp.html'})class MyComponent { message:string; constructor() { this.message = 'World'; }}
Avec template
<span>Hello {{message}} !</span>
cmp.html
#XebiConFr
@VIEW
@Component({ selector: 'my-component', templateUrl: 'cmp.html', directives: []})class MyComponent { message:string; constructor() { this.message = 'World'; }}
dans @Component
#XebiConFr
PROPERTIES: [...]Input API
#XebiConFr
PROPERTIES
<input type="text" value="foo">
Html
input: ... type: "text" value: "foo" ...
Node
#XebiConFr
PROPERTIES
<img src="{{myImage}}">
Angular 1
<img [src]="myImage">
Angular 2
<div ng-hide="isHidden">Hidden if isHidden is true </div><my-component model="{{something}}"></my-component>
<div [hidden]="isHidden">Hidden if isHidden is true </div><my-component [model]="something"></my-component>
#XebiConFr
PROPERTIESDéclaration
Utilisation<my-component [model]="data"></my-component>
@Component({ selector: 'my-component'})class MyComponent { @Input() model:any; // <-- declaration des properties
show() { console.log(this.model); }}
#XebiConFr
EVENTS: (...)Output API
#XebiConFr
EVENTS
<my-component select="myFunction()"></my-component>
Angular 1
<my-component (select)="myFunction()"></my-component>
Angular 2
<div ng-click="doSomething()"></div>
<div (click)="doSomething()"></div>
#XebiConFr
EVENTS
@Component({ selector: 'my-component' })class MyComponent { @Output() event:EventEmitter = new EventEmitter(); // declaration
fireMyEvent(data:string) { this.event.next({value: data}); }}
Déclaration
Utilisation<my-component (event)=”myFunction($event.value)”></my-component>
#XebiConFr
ONE WAY DATA BINDING
Two-Way data-binding
#XebiConFr
FLUX DE DONNÉES
● Entrées via "bindings" des proprietés● Sorties via "bindings" des événements
#XebiConFr
LOCAL VARIABLES: #
<input type="text" #user (keyup)>
{{user.value}}
<button (click)="user.focus()">Grab focus</button>
#XebiConFr
Les composants sont auto-descriptifs
Component = Application
#XebiConFr
MODULESLa fin d’angular.module(...)
#XebiConFr
ES 6 EVERYWHERE !
#XebiConFr
PARTAGE DE MODULE
export default i => i + MY_CONST;export class MyDirective {};export const MY_CONST = 1;
my-module.js
#XebiConFr
UTILISATION D’UN MODULE
import myThing, {MyDirective, MY_CONST} from 'my-module';
depends-on-my-module.js
#XebiConFr
SERVICESLa fin d’ angular.factory(...) et angular.provider(...)
#XebiConFr
SERVICEmy-service.js
export class SlotService { getSlots() { return fetch('http://localhost:8000/xke-slots.json' ) .then((response) => response.json()); }}
import {SlotService} from 'slots-service';...class MyComponent { // injection des service}
Utilisation
#XebiConFr
INJECTIONDE DÉPENDANCES
#XebiConFr
Défauts :● Cache interne● Seulement synchrones● Collision d’espace de noms● Indivisible du framework
Injection de dépendances en Angular 1
#XebiConFr
Angular 1 vs Angular 2
Angular 1 Angular 2
Visibilité : Chaîne de prototypes
#XebiConFr
@Component({ selector: 'app' })@View({ template: '<h1>Hello {{ name }} !</h1>' })class App { constructor() { this.name = 'World'; }}
bootstrap(App);
Utilisation (Root injector)@Component({ selector: 'app' })@View({ template: '<h1>Hello {{ name }} !</h1>' })class App { constructor() { this.name = 'World'; }}
bootstrap(App, [NameService]);
class NameService { getName() { ... }}
@Component({ selector: 'app' })@View({ template: '<h1>Hello {{ name }} !</h1>' })class App { constructor(@Inject(NameService) nameService) { this.name = nameService.getName(); }}
bootstrap(App, [NameService]);
@Component({ selector: 'app' })@View({ template: '<h1>Hello {{ name }} !</h1>' })class App { constructor(nameService: NameService) { this.name = nameService.getName(); }}
bootstrap(App, [NameService]);
#XebiConFr
Utilisation (Providers)
#XebiConFr
Utilisation (Providers)@Component({ selector: 'app'})@View({ template: '<h1>Hello <name-comp></name-comp>!</h1>'})class App { ... }
import {NameService} from 'name-service';
@Component({ selector: 'name-comp', providers: [NameService]})@View({ template: '...'})class NameComponent { constructor(nameService: NameService) { ... }}
#XebiConFr
Injecter “à la main”import { Injector } from 'angular2/angular2';
var injector = Injector.resolveAndCreate([Car, Engine, Tires, Doors]);var car = injector.get(Car);
class Car { constructor(engine: Engine, tires: Tires, doors: Doors) { ... }}
import { bind } from 'angular2/angular2';
var injector = Injector.resolveAndCreate([ bind(Car).toClass(Car), bind(Tires).toClass(Tires), bind(Doors).toClass(Doors), bind(Engine).toClass(OtherEngine)]);
#XebiConFr
DIRECTIVES
#XebiConFr
● directive : décorateur sans vue● component : directive avec une vue
DIRECTIVES
#XebiConFr
NG-IF, NG-FOR...import {NgFor, NgIf} from 'angular2/angular2' ;...
@Component...@View({ template: `Hello <span * ng-if="fl">World</span> ! <div *ng-for="#item of items">{{item}}</div>`, directives: [NgFor, NgIf]})export class MyComponent { fl:Boolean = false; items:Array<string> = ['First item', 'Second item', 'Third item']; constructor() { setTimeout(() => this.fl = true, 2000); }}
#XebiConFr
NEW ROUTERInspiré par Ember.Js / RouteReconizer
#XebiConFr
1 ROUTE → 1 COMPOSANT
@View({
template: "Contenu page 1"
})
export class Route1 {}
@View({
template: "Contenu page 2"
})
export class Route2 {}
my-routes.js
#XebiConFr
1 DÉCORATEUR → N ROUTES
import {Route1, Route2} from 'my-routes';
@RouteConfig([ {path: '/', component: Route1}, {path: '/route1', component: Route1, as: 'Route1'}, {path: '/route2', component: Route2, as: 'Route2'}])@Component(...)export class App {}
my-app.js
#XebiConFr
1 VUE → 1 “OUTLET”
<a [router-link]="['./Route1']">Page 1</a>
<a [router-link]="['./Route2']">Page 2</a>
<router-outlet></router-outlet>
my-app.html
#XebiConFr
Questions
?
#XebiConFr
WORKSHOPhttp://github.com/xebia-france/slot-angular2
#XebiConFr
TESTSTester, ce n’est sûrement pas douter !
#XebiConFr
✓ Tests de services : avec Jasmine + Angular✗ Tests de composants (avec / sans DOM)✗ Tests bout-en-bout
MATURITÉ PAR NIVEAU DE TEST
https://angular.io/docs/ts/latest/testing/
#XebiConFr
ZONE.JSLe dirty-checking version 2.0
#XebiConFr
C’est quoi ? un contexte d'exécution partagé
Oui mais… pour faire quoi ?● éviter les $apply explicites● un seul $digest cycle● debugging : des erreurs console intelligibles
ZONE.JS D’APPLICATION
#XebiConFr
PERFORMANCESDu mieux, en mieux
#XebiConFr
time (ms) / # of items
source : http://info.meteor.com/blog/comparing-performance-of-blaze-react-angular-meteor-and-angular-2-with-meteor
COMPARATIF