Vous êtes sur la page 1sur 202

Angular

Sommaire
Rappels

Prsentation
DmarreruneapplicationAngular
Tests
Template,Directives&Composants
LesdirectivesAngular
InjectiondeDpendances
LesPipes
ServiceHTTP

Router
GestiondesFormulaires
ServersideRendering

Copyright2017Zenika.Allrightsreserved
Logistique

Horaires
Djeuner&pauses
Autresquestions?

Copyright2017Zenika.Allrightsreserved
Copyright2017Zenika.Allrightsreserved
Rappels

1
Sommaire
Rappels

Prsentation
DmarreruneapplicationAngular
Tests
Template,Directives&Composants
LesdirectivesAngular
InjectiondeDpendances
LesPipes
ServiceHTTP

Router
GestiondesFormulaires
ServersideRendering

Copyright2017Zenika.Allrightsreserved 11
Introduction

LangagecrparAndersHejlsbergen2012

ProjetopensourcemaintenuparMicrosoft(Versionactuelle2.1)
InfluencparJavaScript,JavaetC#
Alternatives:CoffeeScript,Dart,HaxeouFlow

Copyright2017Zenika.Allrightsreserved 12
Introduction

PhasedecompilationncessairepourgnrerduJavaScript

AjoutdenouvellesfonctionnalitsaulangageJavaScript
Supportd'ES3/ES5/ES2015

Certainesfonctionnalitsn'ontaucunimpactsurleJavaScriptgnr
ToutprogrammeJavaScriptestunprogrammeTypeScript

Copyright2017Zenika.Allrightsreserved 13
TypeScript - Fonctionnalits

Typage

Gnriques
Classes/Interfaces/Hritage

Dveloppementmodulaire
Lesfichiersdedfinitions
Mixins

Dcorateurs
FonctionnalitsES2015

Copyright2017Zenika.Allrightsreserved 14
Types primitifs

Pourdclarerunevariable:
var variableName: variableType = value;
let variableName2: variableType = value;
const variableName3: variableType = value;

boolean:let isDone: boolean = false;

number:let height: number = 6;

string:let name: string = 'Carl';

array:let names: string[] = ['Carl', 'Laurent'];

any:let notSure: any = 4;

Copyright2017Zenika.Allrightsreserved 15
Fonctions

CommeenJavaScript,possibilitdecrerdesfonctionsnommesou
anonymes
//Fonction nomme
function namedFunction():void { }

//Fonction anonyme
let variableAnonymousFunction = function(): void { }

Peutretournerunevaleurgrceaumotclreturn

Accsauxvariablesdfiniesendehorsduscopedelafonction
let externalScope:number = 10;

function add(localArg: number): number { return localArg + externalScope; }

Copyright2017Zenika.Allrightsreserved 16
Fonctions - Paramtres (Optionels)

Unefonctionpeutprendredesparamtres
function fn(name: string, forename: string) { }

Unparamtrepeuttreoptionel

utilisationducaractre?

ordrededfinitiontrsimportant
aucuneimplicationdanslecodeJavaScriptgnr
sipasdfini,leparamtreauralavaleurundefined
function fn(name: string, forename?: string) { }

Copyright2017Zenika.Allrightsreserved 17
Arrays

Permetdemanipuleruntableaud'objet

2syntaxespourcrerdestableaux
SyntaxeLitrale
let list: number[] = [1, 2, 3];

SyntaxeutilisantleconstructeurArray
let list: Array<number> = [1, 2, 3];

Ces2syntaxesaboutirontaummecodeJavaScript

Copyright2017Zenika.Allrightsreserved 18
Type Enum

Possibilitdedfiniruntypepourexpliciterunensemblededonnes
numriques
enum Music { Rock, Jazz, Blues };

let c: Music = Music.Jazz;

Lavaleurnumriquecommencepardfaut0

Possibilitdesurchargerlesvaleursnumriques
enum Music { Rock = 2, Jazz = 4, Blues = 8 };

let c: Music = Music.Jazz;

Rcuprationdelachanedecaractresassocielavaleurnumrique
let style: string = Music[4]; //Jazz

Copyright2017Zenika.Allrightsreserved 19
Classes

Systmedeclassesetinterfacessimilairelaprogrammationoriente
objet

Lecodejavascriptgnrutiliseralesystmedeprototype

Possibilitdedfinirunconstructeur,desmthodesetdesproprits

Proprits/mthodesacccessiblesvial'objetthis
class Person {
constructor() {}
}

let person = new Person();

Copyright2017Zenika.Allrightsreserved 110
Classes - Mthodes

Mthodesajoutesauprototypedel'objet

VersionTypeScript

class Person {
constructor() {}

sayHello(message: string) { }
}

VersionJavaScript
var Person = (function () {
function Person() { }
Person.prototype.sayHello = function (message) { };
return Person;
})();

Copyright2017Zenika.Allrightsreserved 111
Classes - Proprits

Troisscopesdisponibles:public,privateetprotected

Utiliselescopepublicpardfaut

ScopeprotectedapparuenTypeScript1.3

Propritsajoutessurl'objetencoursd'instanciation(this)

Possibilitdedfinirdespropritsstatiques(static)

Touslestypessupports:typesprimitifs,fonctions,...

Propritajouteauconstructeurdel'objet

Copyright2017Zenika.Allrightsreserved 112
Classes - Proprits

VersionTypeScript
class Person {
firstName: string;
constructor(firstName: string){
this.firstName = firstName;
}
}

VersionJavaScript
var Person = (function () {
function Person(firstName) {
this.firstName = firstName;
}
return Person;
})();

Copyright2017Zenika.Allrightsreserved 113
Classes - Proprits

Secondeversionpourinitialiserdesproprits

VersionTypeScript
class Person {
constructor(public firstName: string) { }
}

VersionJavaScript
var Person = (function () {
function Person(firstName) {
this.firstName = firstName;
}
return Person;
})();

Copyright2017Zenika.Allrightsreserved 114
Classes - Accesseurs

Possibilitdedfinirdesaccesseurspouraccderuneproprit
Utiliserlesmotsclgetetset
Attentionl'espacementapreslesmotscl

NcessitdegnrerducodeJavaScriptcompatibleES5
LecodeJavaScriptgnrutiliseraObject.defineProperty
class Person {
private _secret: string;
get secret(): string{
return this._secret.toLowerCase();
}
set secret(value: string) {
this._secret = value;
}
}

let person = new Person();


person.secret = 'Test';
console.log(person.secret); // Copyright2017Zenika.Allrightsreserved
=> 'test' 115
Classes - Hritage

Systmed'hritageentreclassesvialemotclextends

Siconstructeurnondfini,excuteceluidelaclasseparente
Possibilitd'appelerl'implmentationdelaclasseparenteviasuper

Accsauxpropritsdelaclasseparentesipublicouprotected
class Person {
constructor() {}
speak() {}
}

class Child extends Person {


constructor() { super() }
speak() { super.speak(); }
}

Copyright2017Zenika.Allrightsreserved 116
Interfaces

Utilisesparlecompilateurpourvrifierlacohrencedesdiffrentsobjets

AucunimpactsurleJavaScriptgnr
Systmed'hritageentreinterfaces

Plusieurscasd'utilisationpossible
Vrificationdesparamtresd'unefonction
Vrificationdelasignatured'unefonction
Vrificationdel'implmentationd'uneclasse

Copyright2017Zenika.Allrightsreserved 117
Interfaces - Implmentation d'une classe

Casd'utilisationleplusconnudesinterfaces

Vrificationdel'implmentationd'uneclasse
Erreurdecompilationtantquelaclassenerespectepaslecontratdfinipar
l'interface
interface Musician {
play(): void;
}

class TrumpetPlay implements Musician {


play() {}
}

Copyright2017Zenika.Allrightsreserved 118
Gnriques

Fonctionnalitpermettantdecrerdescomposantsrutilisables

InspirationdesgnriquesdisponiblesenJavaouC#
Ncessitdedfinirun(ouplusieurs)paramtre(s)detypesurla
fonction/variable/classe/interfacegnrique
function identity<T>(arg: T): T {
return arg;
}

identity(5).toFixed(2); // Correct

identity('hello').toFixed(2); // Incorrect

identity(true);

Copyright2017Zenika.Allrightsreserved 119
Gnriques

Possibilitdedfiniruneclassegnrique

Dfinitiond'unelistedeparamtresdetypedemanireglobale
class Log<T> {
log(value: T) {
console.log(value);
}
}

let numericLog = new Log<number>();

numericLog.log(5); // Correct
numericLog.log('hello'); // Incorrect

Copyright2017Zenika.Allrightsreserved 120
NPM

Nodeinclutunsystmedegestiondespaquets:npm

IlexistepratiquementdepuislacrationdeNode.js
C'estuncanalimportantpourladiffusiondesmodules

Copyright2017Zenika.Allrightsreserved 121
npm install

npmestunoutilenlignedecommande(critavecNode.js)

Ilpermetdetlchargerlesmodulesdisponiblessur npmjs.org
Lescommandeslespluscourantes:

install:tlchargelemoduleetleplacedanslerpertoirecourant
dans./node_modules

install -g:installationglobale,lemoduleestplacdanslerpertoire
d'installationdeNode.js
Permetderendreaccessibledescommandes
update:metjourunmoduledjinstall

remove:supprimelemoduleduprojet

Copyright2017Zenika.Allrightsreserved 122
npm init

npmgregalementladescriptionduprojet

UnmoduleNode.jsestun(ouplusieurs)script(s)
Lefichierdeconfigurationsenommepackage.json

npmpermetgalementdemanipulerlemodulecourant

init:initialiseunfichierpackage.json
docs:gnreladocumentationdumoduleencours

install --saveou--save-dev:
Commeinstallmaisrfrenceautomatiquementladpendancedansle
package.json

Copyright2017Zenika.Allrightsreserved 123
package.json

npmsebasesurunfichierdescripteurduprojet

package.jsondcritprcismentlemodule

Onytrouvediffrentstypesd'information

Identification
name:l'identifiantdumodule(unique,urlsafe)

version:doitrespecter nodesemver

Description:description,authors,...

Dpendances:dependencies,devDependencies,...

Cycledevie:scriptsmain,test,...

Copyright2017Zenika.Allrightsreserved 124
package.json : dpendances

dependencies
Lalistedesdpendancesncessaireslexcution

devDependencies
Lesdpendancespourlesdveloppements(build,test...)
peerDependencies
Lesdpendancesncessairesaubonfonctionnementdumodule,maispas
installeslorsd'unnpm install

optionalDependencies(rare)
Desdpendancesquinesontpasindispensablesl'utilisationdumodule
prendencomptequelarcuprationpeutchouer
bundledDependencies(rare)
Desdpendancesquisontpubliesetlivresaveclemodule

Copyright2017Zenika.Allrightsreserved 125
package.json : versions

Lesmodulesdoiventsuivrelanorme semver

Structure:MAJOR.MINOR.PATCH

MAJOR:Changementsd'APIincompatibles

MINOR:Ajoutdefonctionnalitrtrocompatible

PATCH:Correctiondebugs
Pourspcifierlaversiond'unedpendance

version:doittreexactementcetteversion

~,^:approximativement,compatible

major.minor.x:xfaitofficedejoker
Etbiend'autres :>,<,>=,min-max...

Copyright2017Zenika.Allrightsreserved 126
Publier un module npm

Ilestbiensrconseilldesuivretouteslesbonnespratiques

Utiliserlanumrotationrecommande
Avoirdestestsunitaires

Avoirunminimumd'informationsdanslepackage.json

Iln'yapasd'autoritdevalidation
Ilfautparcontretrouverunnomdisponible

Lasuitencessiteseulementlacommandenpm

npm adduser:enregistrersoncompte

npm publish:uploaderunmodulesur npmjs.org

Copyright2017Zenika.Allrightsreserved 127
Copyright2017Zenika.Allrightsreserved 128
Prsentation

2
Sommaire
Rappels

Prsentation
DmarreruneapplicationAngular
Tests
Template,Directives&Composants
LescomposantsAngular
InjectiondeDpendances
LesPipes
ServiceHTTP

Router
GestiondesFormulaires
ServersideRendering

Copyright2017Zenika.Allrightsreserved 21
Prsentation

FrameworkcrparGoogleetannoncen2014
Rcrituretotalduframework
Reprendcertainsconceptsd'AngularJS

1eversionbetaannoncele23/10/2014
Versionofficiellesortieen2016
ProgrammationorienteComposant

Frameworkconupourtreplusperformantetoptimispourlesmobiles
http://angular.io/

Copyright2017Zenika.Allrightsreserved 22
Points ngatifs d'AngularJS

DiffrencesentrelesdirectivesetngController

Twowaydatabindingsourcedeproblmesdeperformance
Hirarchiedesscopes

Pasdeserversiderendering
Plusieurssyntaxespourcrerdesservices
APIdesdirectivestropcomplexe

APImalconuencessitantl'utilisantdefix(ngModelOptions)

Copyright2017Zenika.Allrightsreserved 23
Points ngatifs d'AngularJS - directive

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

VersionAngular:
import { Component, Input} from '@angular/core'
@Component({
selector: 'my-directive'
})
export class MyDirective {
@Input() variable:string;
}

Copyright2017Zenika.Allrightsreserved 24
Points ngatifs d'AngularJS - service

APIpourcrerdesservicesenAngularJS
//provider, factory, constant et value
app.service('Service', function(){
let vm = this;
vm.myMethod = function(){

}
});

VersionAngular
@Injectable()
export class Service {

myMethod(){

Copyright2017Zenika.Allrightsreserved 25
Angular - Points Positifs

Crationd'applicationmodulaire

Utilisableavecplusieurslangagesdeprogrammation:ES5,ES2015(ES6),
TypeScriptetDart

APIplussimplequeAngularJS

Seulstroistypesd'lmentsserontutiliss:directive,pipeetles
services

Bassurdesstandards:Web Component,Decorator,ES2015,ES7

Nouvellesyntaxeutilisedanslestemplates

Performancedel'APIChange Detection

LeProjetUniversal

Librairiepourcommencerlamigration:ngUpgrade

CollaborationavecMicrosoftetEmber
Copyright2017Zenika.Allrightsreserved 26
Angular - Points Ngatifs

Nouvellephased'apprentissageduframework

Faibleecosystmepourl'instant
ApplicationAngularJSincompatibleaveccettenouvelleversion

ngUpgradepermetderendrecompatiblelesdirectives,composantet
services
Denouveauxconceptsapprendre:
Zone

Observable

WebPack...

Copyright2017Zenika.Allrightsreserved 27
Angular = Une Plateforme

Angularn'estpasqu'unsimpleframework

IntgrationMobile
Outillagepourfaciliterlaphasededveloppement

Copyright2017Zenika.Allrightsreserved 28
Architecture

Architectured'uneapplicationAngular

Copyright2017Zenika.Allrightsreserved 29
Architecture

Modules:regroupementd'unensembledefonctionnalitssousunmme
namespace

LibraryModules(barrels):@angular/core,@angular/http...
Lescomposants:Elmentgraphiquecomposd'untemplateetd'uneclasse

Mtadata:Moyend'indiquerAngularcommentutiliserlaclasse
Directives:composantssanstemplate(ngFor,ngIf,...)
Services:Codemtierimplmentdansdesclassesquiserontinjectes
danslesdiffrentscomposants

Pipe:Elmentpermettantdeformatterunedonne(quivalentaufilter
d'AngularJS)

Copyright2017Zenika.Allrightsreserved 210
Architecture - Exemple complet

Exemplecompletutilisantlesdiffrentesbriquesd'uneapplicationAngular
import {Component} from '@angular/core';
import {Http} from '@angular/http';

@Component({
selector: 'app',
template: '{{value | MyPipe}}'
})
export class MyComponent{
value:string;
constructor(http:Http){
}
}

Copyright2017Zenika.Allrightsreserved 211
Copyright2017Zenika.Allrightsreserved 212
Dmarrer une
application Angular

3
Sommaire
Rappels

Prsentation
DmarreruneapplicationAngular
Tests
Template,Directives&Composants
LescomposantsAngular
InjectiondeDpendances
LesPipes
ServiceHTTP

Router
GestiondesFormulaires
ServersideRendering

Copyright2017Zenika.Allrightsreserved 31
Commencer un nouveau projet

GestiondesdpendancesviaNPM

lesdiffrentsmodulesAngular:@angular/common,
@angular/core...

Webpack:gestiondesmodules

RxJS:gestiondel'asynchrone
npm init
npm install --save @angular/common @angular/core rxjs ...

InitialisationetConfigurationd'unprojetTypeScript

Configurationdusystmedegestiondesmodules(Webpack)
Installationdesfichiersdedfinition(typings,npmpourTypeScript2.0)

Ncessitd'utiliserunserveurWeb
Apache,serve,live-server...
Copyright2017Zenika.Allrightsreserved 32
Commencer un nouveau projet

Crationducomposantprincipal

dfinirleslecteurncessairepourutiliserlecomposant
crireletemplate

implmenterlaclasseTypeScript
import { Component } from '@angular/core'

@Component({
selector: 'app',
template: `<p>Hello</p>`
})
export class AppComponent { ... }

Copyright2017Zenika.Allrightsreserved 33
Commencer un nouveau projet

Crationd'unmoduleAngular
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';

@NgModule({
declarations: [
AppComponent,
],
imports: [
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}

platformBrowserDynamic().bootstrapModule(AppModule);

Copyright2017Zenika.Allrightsreserved 34
Angular-CLI

Projetencoursdedveloppement

BassurleprojetEmberCLI
Permetdecrerlesqueletted'uneapplication

TypeScript,WebPack,Karma,Protractor,PrprocesseursCSS...
ProjetdisponiblesurNPM
npm install -g angular-cli

Plusieurscommandesdisponibles
ng new Application
ng build (--dev / --prod)
ng serve

ng generate component Product (--inline-template) // => class ProductComponent{


... }
ng generate pipe UpperCase
ng generate service User
ng generate directive myNgIf Copyright2017Zenika.Allrightsreserved 35
Angular-CLI

D'autrescommandesdisponibles:

ng test

ng e2e

ng lint

Copyright2017Zenika.Allrightsreserved 36
WebPack

Gestionnairedemodules

Supportelesdiffrentssystmesdemodules(CommonJS,AMD,ES2015,
...)
DisponiblesurNPM:npm install -g webpack

Construitungraphedetouteslesdpendancesdevotreapplication
configurationviaunfichierdeconfigurationJavaScript
(webpack.config.js)

loaders:ES2015,TypeScript,CSS,...

preloaders:JSHint,...
plugins:Uglify,...

Copyright2017Zenika.Allrightsreserved 37
WebPack - Premier exemple

PremireutilisationdeWebPack
//app.js
document.write('welcome to my app');
console.log('app loaded');

ExcutiondeWebPackpourgnrerunfichierbundle.js
webpack ./app.js bundle.js

Importdevotrefichierbundle.jsdansvotreindex.html
< html>
< body>
< script src="bundle.js">< /script>
</ body>
</ html>

Copyright2017Zenika.Allrightsreserved 38
WebPack

Versionavecunfichierdeconfiguration

solutionprivilgierpourquetouslesdveloppeursutilisentlamme
configuration
module.exports = {
entry: "./app.js",
output: {
filename: "bundle.js"
}
}

webpack

Copyright2017Zenika.Allrightsreserved 39
WebPack - Conguration

Possibilitdegnrerplusieursfichiers

Utilisationduplaceholder[name]
entry: {
app: 'src/app.ts',
vendor: 'src/vendor.ts'
},
output: {
filename: '[name].js'
}

Crationd'unfichiervendor.tsimportanttouteslibrairiesutilises
// Angular
import '@angular/core';
import '@angular/common';
import '@angular/http';
import '@angular/router';
// RxJS
import 'rxjs';

Copyright2017Zenika.Allrightsreserved 310
WebPack - Conguration

Possibilitderegnrerlebundle.jschaquemodificationdessources
(watch)

Serveurwebdisponible(webpack-dev-server)

HotReloading

ModeWatchactive
Gnrationdufichierbundle.jsenmmoire

Copyright2017Zenika.Allrightsreserved 311
WebPack - Les Loaders

Permetd'indiquerWebPackcommentprendreencompteunfichier

Plusieursloadersexistent:ECMAScript2015,TypeScript,CoffeeScript,
Style,...
entry: {
app: 'src/app.ts',
vendor: 'src/vendor.ts'
},
resolve: {
extensions: ['', '.js', '.ts']
},
module: {
loaders: [{
test: /\.ts$/,
loaders: ['ts']
}]
},
output: {
filename: '[name].js'
}

Copyright2017Zenika.Allrightsreserved 312
WebPack - Les Plugins

Permetd'ajouterdesfonctionnalitsvotreworkflowdebuild
entry: {
app: 'src/app.ts',
vendor: 'src/vendor.ts'
},
resolve: {
extensions: ['', '.js', '.ts']
},
module: {
loaders: [{
test: /\.ts$/,
loaders: ['ts']
}]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({name: ['app', 'vendor']}),

new HtmlWebpackPlugin({template: 'src/index.html'})


]
output: {
filename: '[name].js'
}
Copyright2017Zenika.Allrightsreserved 313
WebPack - Autres outils

L'optimisationd'uneapplicationAngularpeuttredcoupeen4phases:

Offlinecompilation:ngc
Inlinemodules:WebPack

TreeShaking:Rollup
Minification:Uglify

Copyright2017Zenika.Allrightsreserved 314
Copyright2017Zenika.Allrightsreserved 315

TP1
Copyright2017Zenika.Allrightsreserved 316
Les Tests

4
Sommaire
Rappels

Prsentation
DmarreruneapplicationAngular
Tests
Template,Directives&Composants
LesdirectivesAngular
InjectiondeDpendances
LesPipes
ServiceHTTP

Router
GestiondesFormulaires
ServersideRendering

Copyright2017Zenika.Allrightsreserved 41
Concepts

DansladocumentationJasmineestutiliscommeframeworkdetests

Angularpeuttregalementtestavecd'autresframeworks

Karmaproposedexcuterfacilementlestests

Ilatdveloppparl'quiped'AngularJS,ilestdoncmisenavant

Iln'estpourautantniindispensableniliAngular

JasmineetKarmasontintgrsdansuneapplicationgnreparangular
cli.

Copyright2017Zenika.Allrightsreserved 42
Tests - Utilisation de Jasmine

FrameworkdeTests: http://jasmine.github.io/
Aucunedpendanceversd'autresframeworks

Nencessitepasd'lmentduDOM
EssayerJasmineenligne: http://tryjasmine.com/

Copyright2017Zenika.Allrightsreserved 43
Tests - Structure d'un test Jasmine

Mthodesdescribeetitpourdcrirelasuitedetests

Systmedematchers:toBe,toBeUndefined,toBeTruthy,toThrow,
...
Possibilitd'utiliserleslibrairiesChaiouSinonJS
describe('True value:', function() {
it('true should be equal to true', function() {

expect(true).toBe(true);

});
});

Copyright2017Zenika.Allrightsreserved 44
Tests - Structure d'un test Jasmine

MthodesbeforeEach,afterEach,beforeAll,afterAll

Excutiond'unefonctionavantouaprschaquetest
describe('True value:', function() {
let value;

beforeEach(function(){
value = true;
});

it('true should be equal to true', function() {


expect(value).toBe(true);
});
});

Copyright2017Zenika.Allrightsreserved 45
Tests - Structure d'un test Jasmine

PossibilitdedfinirdesSpiesgrcelamthodespyOn

Vrifierl'excutiondelamthodeespionne
toHaveBeenCalled,toHaveBeenCalledWith

and.callThrough,and.returnValue,and.callFake...

Spy.calls
describe('Service objet:', function() {

it('checkout method should be called', function() {


spyOn(service, 'foo');
service.foo();
expect(service.foo).toHaveBeenCalled();
});
});

Copyright2017Zenika.Allrightsreserved 46
Tests - Tests TypeScript

Possibilitd'criredestestsenTypeScript
class True {
returnTrue(){ return true; }
}

describe('True object:', () => {


describe('returnTrue method:', () => {
it('should return true', () => {
let trueObject:True = new True();
expect(trueObject.returnTrue()).toBe(true);
});
});
});

Copyright2017Zenika.Allrightsreserved 47
Karma

Karmaestunoutilquipermetd'automatiserlexcutiondestests

Copyright2017Zenika.Allrightsreserved 48
Tests - Automatisation de l'excution des tests

Configurationautomatiquementraliseparangular-cli

Lesfichiersdetestsontautomatiquementcrslorsdelacrationd'un
Composant/Service/Pipeviaangular-cli

Ilssetrouventdanslemmerpertoirequel'lmenttester:mon
service.spec.ts

Excutiondestests:
ng test

Copyright2017Zenika.Allrightsreserved 49
Copyright2017Zenika.Allrightsreserved 410

TP2
Copyright2017Zenika.Allrightsreserved 411
Template, Directives &
Composants

5
Sommaire
Rappels

Prsentation
DmarreruneapplicationAngular
Tests
Template,Directives&Composants
LesdirectivesAngular
InjectiondeDpendances
LesPipes
ServiceHTTP

Router
GestiondesFormulaires
ServersideRendering

Copyright2017Zenika.Allrightsreserved 51
Syntaxe des templates

Systmed'interpolationgrcelasyntaxe{{ expression }}

L'expressionpeuttre:
unechanedecaractre

lavaleurd'unevariable
lavaleurretourned'unefonction
Cetteexpressionseraconvertieenstringavantsonaffichage

Uneexpressionnedoitpasmodifierl'tatdel'application

Copyright2017Zenika.Allrightsreserved 52
Les proprits

Possibilitdedfinirunevaleurpouruneproprit

Diffrentd'AngularJS,onousutilisonslesattributsHTML
Attentionladiffrenceentreattributetproprit

Unattributeststatiquecontrairementuneproprit
SyntaxeidentiquepourlespropritsdeslmentsHTML,descomposants
etdesdirectives
Utilisationdelasyntaxe[ property-name ] = "expression"
<button [disabled]="isUnchanged">Save</button>
<button bind-disabled="isUnchanged">Save</button>

<hero-detail [hero]="currentHero"></hero-detail>

<div [class.special]="isSpecial">Special</div>
<button [style.color] = "isSpecial ? 'red' : 'green'">

Copyright2017Zenika.Allrightsreserved 53
Les proprits

Pourlesattributsn'ayantpasd'quivalencedansl'APIDOM

utilisationduAttribute Binding

Autiliserpouraria,colspan,svgparexemple

Utilisationdelasyntaxe[ attr.attribute-name ] = "expression"


<td [colspan]="dynamicColspan">help</td>

<!-- Template parse errors:


Can't bind to 'colspan' since it isn't a known native property-->

<button [attr.aria-label]="helpLabel">{{helpLabel}}</button>

Copyright2017Zenika.Allrightsreserved 54
Les vnements

Permetd'associeruneexpressionAngularunvnement

dfinidanslaspcificationHTML:click,blur,...

crspcialementpourl'application(avecunesmantiqueprcise)

Lesmthodesetpropritsutilisesdoiventtredfiniesdanslaclasse
associe
Utilisationdelasyntaxe( event-name ) = "expression"

<button (click)="myMethod()"></button>
<hero-detail (deleted)="onHeroDeleted()"></hero-detail>

<button on-click="myMethod()"></button>

Copyright2017Zenika.Allrightsreserved 55
Les vnements

Angularvacrerunhandlerpourchaquevnement

Possibilitdercuprerlecontextedel'vnement,etdepotentielles
donnesvial'objet$event

Cetobjetpeuttreutilisdansl'expressionAngular

Touslesvnementsnatifssontpropagsversleslmentsparents
nousdevonsretournerunevaleurfalsepourstoppercettepropagation

LesvnementsEventEmitternesepropagentpas.
<input [value]="currentHero.firstName"
(input)="currentHero.firstName=$event.target.value"/>

Copyright2017Zenika.Allrightsreserved 56
Syntaxe "Banana in the Box"

Le2waydatabindingestdsactivpardfaut
Poursynchroniserunchampdeformulaireavecunevariable,ncessit
d'utilisercettesyntaxe
<input [value]="currentHero.firstName"
(input)="currentHero.firstName=$event.target.value"/>

Angularfournitdusucresyntaxiqueafind'vitercetteredondancedecode

Premiresolution:
<input
[ngModel]="currentHero.firstName"
(ngModelChange)="currentHero.firstName=$event"/>

Deuximesolution:
<input [(ngModel)]="currentHero.firstName"/>

Copyright2017Zenika.Allrightsreserved 57
Les Directives

Portiondecodepermettantdedfinirl'apparenceoulefonctionnementd'un
lmentHTML

L'lmentHTMLestslectionnparuneexpressionCSS

Crationdedirectivepersonnaliseavecl'annotation@Directive

Utiliserunprfixepourlesnomsdevosdirectivespourviterlesconflits
PourfairedelamanipulationdeDOM,toujoursutiliserleserviceRenderer
//<span myHighlight>Highlight me!</span>
import {Directive, ElementRef, Renderer, Input} from '@angular/core';
@Directive({
selector: '[myHighlight]'
})
export class HighlightDirective {
constructor(el: ElementRef, renderer: Renderer) {
//el.nativeElement.style.backgroundColor = 'yellow';
renderer.setElementStyle(el.nativeElement, 'backgroundColor', 'yellow');
}
}
Copyright2017Zenika.Allrightsreserved 58
Les Directives - Action utilisateur

Possibilitd'couterlesvnementsdel'lmentsurlequelestplacla
directive

Utilisationdelaproprithostdel'annotation@Directive

L'ajoutd'handlerprogrammatiquementestviterpourdesproblmesde
mmoire

Possibilitd'utiliserlesdcorateursHostListeneretHostBinding
import {Directive, ElementRef, Renderer, Input} from '@angular/core';
@Directive({
selector: '[myHighlight]',
host: {
'(mouseenter)': 'onMouseEnter()',
'(mouseleave)': 'onMouseLeave()'
}
})
export class HighlightDirective {
constructor(private el: ElementRef, private renderer: Renderer) { ... }
onMouseEnter() { this._highlight("yellow"); }
onMouseLeave() { this._highlight(null); }
Copyright2017Zenika.Allrightsreserved 59
Les Directives - Les paramtres

Unedirectivepourratreparamtrable

Dclarationd'unevariabledeclasseannote@Input

Lenomdelavariabledeclassequiserautilisedansletemplate
//<p [myHighlight]="color">Highlight me!</p>
export class HighlightDirective {
@Input('myHighlight') highlightColor: string;
private _defaultColor = 'red';

constructor(private el: ElementRef, private renderer: Renderer) { }

onMouseEnter() { this._highlight(this.highlightColor || this._defaultColor);


}
onMouseLeave() { this._highlight(null); }

private _highlight(color:string) {
this.renderer
.setElementStyle(this.el.nativeElement, 'backgroundColor', color);
}
}
Copyright2017Zenika.Allrightsreserved 510
Les Directives - Les vnements

Delammefaon,unedirectivepourramettreunvnement

Dclarationd'unevariabledeclasseannote@Outputdetype
EventEmitter

Lenomdelavariablecorrespondaunomdel'vnementquiserautilis
dansl'HTML

L'vnementestmislorsdel'appeldelamthodeemit

Possibilitdepasserdesparamtres,accessiblesdepuisl'objet$event
//<p [myHighlight]="color" (hightLightEvent)="callExpression($event)">Highlight
me!</p>
export class HighlightDirective {
@Output() hightLightEvent = new EventEmitter<string>();

constructor(private el: ElementRef, private renderer: Renderer) { }


onMouseEnter() {
this.hightLightEvent.emit(this.highlightColor);
this._highlight(this.highlightColor || this._defaultColor);
}
Copyright2017Zenika.Allrightsreserved 511
Les Composants

Lescomposantssontdesdirectivesavecuntemplate

Utilisationdel'annotation@Component,hritantde@Directive

Toutelaconfigurationde@Directiveestdisponibledans@Component

Possibilitdedfinirdesparamtresetdesvnementsdelammefaon
@Componentfournitnotammentlesparamtrestemplate,templateUrl,
styles,styleUrlsetencapsulation
import {Input, Output, EventEmitter, Component} from '@angular/core'
import {Product} from './model/Product'

@Component({
selector: 'product-detail',
template: `<article>{{product.name}} <button
(click)="addToBasket.emit(product)"></button></article>`
})
export class ProductComponent {
@Input() product:Product;
@Output() addToBasket = new EventEmitter<Product>();
} Copyright2017Zenika.Allrightsreserved 512
Les Composants - Aggrgation

Lescomposantsexternesncessairesvotreapplicationsdoivent:

tredfinisdansunmoduleimportparvotreapplication(ngModule)

tredfinisdanslapropritdeclarationsdudcorateurngModule
devotreapplication
import { NgModule, ApplicationRef } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';

@NgModule({
declarations: [
AppComponent,
],
imports: [
CommonModule,
FormsModule
]
})
export class AppModule {}
Copyright2017Zenika.Allrightsreserved 513
Les Composants - Aggrgation

Permetd'insrerlecontenuenfantdfinilorsdel'utilisationducomposant

CorrespondladirectivengTranscludeenAngularJS

Possibilitd'avoirplusieurspointsd'insertion(utilisationdelaproprit
select)

LapropritselectacceptecommevaleurunslecteurCSS
//<post><h2>Title</h2><p>Content</p></post>
import {Component} from '@angular/core';
@Component({
selector: 'post',
template: `<article>
<header><ng-content select="h2"></ng-content></header>
<section><ng-content select="p"></ng-content></section>
</article>`
})
export class PostComponent { }

Copyright2017Zenika.Allrightsreserved 514
Les Composants - Tests

Ncessitdeconfigurerl'objetTestBedviasamthode
configureTestingModule:
TestBed.configureTestingModule({
declarations: [
TitleComponent
],
imports: [
// HttpModule, FormsModule, etc.
],
providers: [
// TitleService,
// { provide: TitleService, useClass: TitleServiceMock })
]
});

LamthodecreateComponentdel'objetTestBedretourneunobjetde
typeComponentFixturequiestunereprsentationducomposant

Copyright2017Zenika.Allrightsreserved 515
Les Composants - Tests

UnobjetdetypeComponentFixtureproposedeuxproprits
intressantes:

componentInstance:l'instanceJavaScriptducomposant

nativeElement:l'lmentHTML

Pourexcuterl'APIChangeDetection,utilisationdelamthode
detectChanges
@Component({
selector: 'title', template: '<h1>{{title}}</h1>'
})
export class TitleCmp {
@Input() title: string;
}

Copyright2017Zenika.Allrightsreserved 516
Les Composants - Tests

TestUnitaire:
import {TestBed, async} from '@angular/core/testing';

import {TitleComponent} from './title.component';


describe('TitleComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TitleComponent]
});
});

it('should have a title', async(() => {


let fixture = TestBed.createComponent(TitleComponent);
let instance = fixture.componentInstance;
instance.title = 'Hello World';
fixture.detectChanges();

let element = fixture.nativeElement;


expect(element.querySelector('h1').textContent).toBe('Hello World');
}));
});

Copyright2017Zenika.Allrightsreserved 517
Copyright2017Zenika.Allrightsreserved 518

TP3
Copyright2017Zenika.Allrightsreserved 519
Les directives
Angular

6
Sommaire
Rappels

Prsentation
DmarreruneapplicationAngular
Tests
Template,Directives&Composants
LesdirectivesAngular
InjectiondeDpendances
LesPipes
ServiceHTTP

Router
GestiondesFormulaires
ServersideRendering

Copyright2017Zenika.Allrightsreserved 61
Les directives Angular

Angularfournitunetrentainededirectives:

ManipulationdeDOM
Gestiondesformulaires

Routeur
Importerlemodulecorrespondantpourlesutiliser:
CommonModule

FormModule

RouterModule

Copyright2017Zenika.Allrightsreserved 62
Les directives Angular - ngStyle

Directivepermettantd'ajouterdesdfinitionsCSS

NcessitdespcifierunobjetJSONentantqueparamtre
import {Component} from '@angular/core';

@Component({
selector: 'ngStyle-example',
template: `
<h1 [ngStyle]="{'font-size': size}">
Title
</h1>

<label>Size:
<input type="text" [value]="size" (change)="size =
$event.target.value">
</label>
`
})
export class NgStyleExample {
size = '20px';
}
Copyright2017Zenika.Allrightsreserved 63
Les directives Angular - ngClass

LadirectivengClassajouteouenlvedesclassesCSS.

Troissyntaxescoexistent
[ngClass]="'class class1'"

[ngClass]="['class', 'class1']"

[ngClass]="{'class': isClass, 'class1': isClass1}"

La3esyntaxeestlapluscourante:

permetdegarderladclarationCSSdanslestemplates

Copyright2017Zenika.Allrightsreserved 64
Les directives Angular - ngClass

Exempled'utilisationdeladirectivengClass
import {Component} from '@angular/core';

@Component({
selector: 'toggle-button',
template: `
<div class="button" [ngClass]="{'disabled': isDisabled}"></divt>
<button (click)="toggle(!isDisabled)">Click me!</button>`,
styles: [`
.disabled {
...
}
`]
})
class ToggleButton {
isDisabled = false;

toggle(newState) { this.isDisabled = newState; }


}

Copyright2017Zenika.Allrightsreserved 65
Les directives Angular - ngFor

Permetdedupliqueruntemplatepourchaquelmentd'unecollection

CorrespondladirectivengRepeatenAngularJS

DfinitiondeslmentsHTMLdupliquerdansunlment<template>

UtilisationdelapropritngForOfpourdfinirl'expressionpermettant
l'itration
Sauvegardedelavaleurencoursdansdesvariablesderendu(prfixes
parlet-)

Angularmetdispositioncinqdonnessupplmentaires:index,first,
last,evenetodd
<template ngFor let-item [ngForOf]="items" let-i="index"><li>...</li></template>

Secondesyntaxedisponible(galementpourngIfetngSwitch)
<li *ngFor="let item of items; let i = index"> {{ item.label }} </li>
Copyright2017Zenika.Allrightsreserved 66
Les directives Angular - ngIf

Ajout/Suppressiond'elementsHTMLenfonctiond'unecondition

Sil'expressionretournetrueletemplateserainsr
<div *ngIf="condition">...</div>
<template [ngIf]="condition"><div>...</div></template>

PasdedirectivesngShowetngHide

Utilisationdelaproprithidden(ncessitedespolyfills)
<div [hidden]="condition">...</div>

Copyright2017Zenika.Allrightsreserved 67
Les directives Angular - ngSwitch

Ajout/Suppressiond'elementsHTMLenfonctiond'unecondition

Troisdirectivesdisponibles:
ngSwitch:lmentcontainer

ngSwitchCase:lmentutiliserpourchaquevaleurpossible

ngSwitchDefault:pourdfiniruntemplatepourunevaleurpardfaut
<div [ngSwitch]="value">
<p *ngSwitchCase="'init'">increment to start</p>
<p *ngSwitchCase="0">0, increment again</p>
<p *ngSwitchCase="1">1, stop incrementing</p>
<p *ngSwitchDefault>&gt; 1, STOP!</p>
</div>

Copyright2017Zenika.Allrightsreserved 68
Copyright2017Zenika.Allrightsreserved 69

TP4
Copyright2017Zenika.Allrightsreserved 610
Injection de
Dpendances

7
Sommaire
Rappels

Prsentation
DmarreruneapplicationAngular
Tests
Template,Directives&Composants
LesdirectivesAngular
InjectiondeDpendances
LesPipes
ServiceHTTP

Router
GestiondesFormulaires
ServersideRendering

Copyright2017Zenika.Allrightsreserved 71
Injecteurs

lmentutilispourinjecterlesservices

Possibilitd'uninjecteurparcomposantcontrairementAngularJS(un
uniqueinjecteurglobal)
Lescomposantshritentdel'injecteurdeleurparent

Ncessitdeconfigurerlesinjecteurs
demanireglobalevialemoduleprincipal@NgModule

demanirelocalevia@Component

Lesservicessontinjectsvialaconstructeurduparentetsontdes
singletonsauseindummeinjecteur

Copyright2017Zenika.Allrightsreserved 72
Conguration globale de l'Injecteur

@NgModuleaunparamtreproviders:untableaudeproviders

LesprovidersdfinitdansunNgModulesontinjectablespartoutdans
l'application
// fichier application.component.ts
import { UserService } from './user.service'

@Component({ ... })
export class AppComponent {
constructor(userService: UserService){
console.log(userService.getUser());
}
}

// fichier app.module.ts
import { UserService } from './services/user.service';

@NgModule({
providers: [ UserService ],
})
export class AppModule { }
Copyright2017Zenika.Allrightsreserved 73
Conguration locale de l'Injecteur

Possibilitdedfinirunepropritprovidersdansl'annotation
@Component

Mmesyntaxequelaconfigurationglobale
LesprovidersdfinitdansunComponentsontinjectablesdansce
componentetsesfils
// fichier application.component.ts
import { UserService } from './user.service'

@Component({
providers: [ UserService ]
})
export class AppComponent {
constructor(userService: UserService){
console.log(userService.getUser());
}
}

Copyright2017Zenika.Allrightsreserved 74
Dpendances des services

Ncessitd'ajouterl'annotation@Injectable

UtilisepourqueAngularpuissegnrerlesmtadatasncessairespour
l'injectiondedpendances
Inutilepourlescomposants,carnousutilisonsdj@Component
import {Injectable} from '@angular/core';
import {Logger} from './logger-service';

@Injectable()
export class MyService {

constructor(public logger:Logger){

}
myMethod(){ ... }

Copyright2017Zenika.Allrightsreserved 75
Congurer les providers

Plusieurssyntaxesexistentpourdfinirlesproviders

L'identifiantduproviderpeuttreunobjet,unechanedecaractresouun
OpaqueToken
export function serverConfigFactory(appService: AppService){
return appService.getConfig();
}
@NgModule({
providers: [
UserService,
{ provide: LoginService, useClass: LoginService },
{
provide: ServerConfig,
useFactory: serverConfigFactory
deps: [AppService]
}
]
})
export class AppModule { }

Copyright2017Zenika.Allrightsreserved 76
Congurer les providers

Lorsquenousavonsdesobjetsinjecter,etnondesclasses

Possibilitdedfinirunechanedecaractrecommeidentifiant
Utilisationdel'objetOpaqueTokendeprfrence

Ncessitd'utiliserl'annotationInjectpourinjectercegenredeservice
let apiUrl: string = 'api.heroes.com';
let env: string = 'dev';

@NgModule({
providers: [{provide: 'apiUrl', useValue:apiUrl},{provide: 'env',
useValue:env}],
})
export class AppModule { }

class AppComponent {
constructor(@Inject('apiUrl') api:string) { ... }
}

Copyright2017Zenika.Allrightsreserved 77
Hirarchie d'injecteurs

Chaquecomposantpeutdfiniruninjecteuravecuncertainnombrede
providers

Chaqueproviderfournitunsingletond'unservice
Siuncomposantabesoind'unservicemaisquesoninjecteurn'apasde
providercorrespondant,ildemandel'injecteurdesonparent

Copyright2017Zenika.Allrightsreserved 78
Hirarchie d'injecteurs

Copyright2017Zenika.Allrightsreserved 79
Injection de Dpendances - Tests

Possibilitdebnficierdel'injectiondedpendancegrcelamthode
inject

Dfinitiondesservicesinjectsdanslestestsvialamthode
configureTestingModuledel'objetTestBed(propritproviders)

Mthodeasyncutilisepourtesterlesservicesasynchrones(utilisele
mchanismedeZone)
import {TestBed, async, inject} from '@angular/core/testing';

describe('UserService', () => {
beforeEach(() => {
TestBed.configureTestingModule({ providers: [UserService] });
});

it('should return 1 user', async(inject([UserService], service => {


service.getUsers().then(users => {
expect(users.length).toBe(1);
});
})));
});
Copyright2017Zenika.Allrightsreserved 710
Copyright2017Zenika.Allrightsreserved 711

TP5
Copyright2017Zenika.Allrightsreserved 712
Les Pipes

8
Sommaire
Rappels

Prsentation
DmarreruneapplicationAngular
Tests
Template,Directives&Composants
LesdirectivesAngular
InjectiondeDpendances
LesPipes
ServiceHTTP

Router
GestiondesFormulaires
ServersideRendering

Copyright2017Zenika.Allrightsreserved 81
Les Pipes

Mcanismepermettantlamanipulationd'unedonneavantsonutilisation

SimilaireauxfiltresdansAngularJS
UtilisationdanslestemplatesHTMLsimilairesl'ancienneversion

PossibilitdedfinirdesPipespureouimpure
Pipesdisponiblespardfautdansleframework(@angular/common):

LowerCasePipe,UpperCasePipe

CurrencyPipe,DecimalPipe,PercentPipe

DatePipe,JSONPipe,SlicePipe

I18nPluralPipe,I18nSelectPipe

AsyncPipe

Copyright2017Zenika.Allrightsreserved 82
Les Pipes - Utilisation dans les Templates

LesPipesdisponiblespardfautsontdirectementutilisablesdansles
templates

LesTemplatesAngularsupportentlecaractre|pourappliquerunPipe

Possibilitdechanerlespipeslesunslasuitedesautres
{{ myVar | date | uppercase}}
//FRIDAY, APRIL 15, 1988

Certainspipessontconfigurables

Sparationdesparamtresparlecaractre:
{{ price | currency:'EUR':true }}

Copyright2017Zenika.Allrightsreserved 83
Les Pipes - Cration

Dfiniruneclasseimplmentantl'interfacePipeTransform

Implmenterlamthodetransform

Annoterlaclasseavecledcorateur@Pipe

Exportercetteclasseviaexport
import {isString, isBlank} from '@angular/core/src/facade/lang';
import {InvalidPipeArgumentError} from
'@angular/common/src/pipes/invalid_pipe_argument_error';
import {PipeTransform, Pipe} from '@angular/core';

@Pipe({name: 'mylowercase'})
export class MyLowerCasePipe implements PipeTransform {
transform(value: string, param1:string, param2:string): string {
if (isBlank(value)) return value;
if (!isString(value)) {
throw new InvalidPipeArgumentError(MyLowerCasePipe, value);
}
return value.toLowerCase();
}
} Copyright2017Zenika.Allrightsreserved 84
Les Pipes - Utilisation

Lespipesexternesncessairesvotreapplicationsdoivent:

tredfinisdansunmoduleimportparvotreapplication(ngModule)

tredfinisdanslapropritdeclarationsdudcorateurngModule
devotreapplication
import {Component} from '@angular/core';

@Component({
selector: 'app',
template: '<h2>{{'Hello World' | mylowercase}}</h2>'
})
export class App { }

Copyright2017Zenika.Allrightsreserved 85
Les Pipes - Utilisation

Utilisationdel'injectiondedpendancespourutiliserunPipe

Pasncessaired'utiliserunservice$filterouunergledenommage
(dateFilter)commeenAngularJS
import {Component} from '@angular/core`;
import {MyLowerCasePipe} from './mylowercase';

@Component({
selector: 'app',
providers: [MyLowerCasePipe]
})
class App {
name:string;

constructor(public lower:MyLowerCasePipe){
this.string = lower.transform('Hello Angular');
}

Copyright2017Zenika.Allrightsreserved 86
Les Pipes - pures et impures

DeuxcatgoriesdePipes:pureetimpure

Pipespurespardfaut:excutseulementquandl'inputdupipesubitun
changement"pure"
changementderfrence

changementd'unevaleurprimitive(boolean,number,string...)
Cecioptimiselesperformancesdumcanismededtectiondechangement
Mais,pastoujourslecomportementsouhait:

ajout/suppressiond'unobjetdansuntableau(larfrencedutableaune
changepas)
modificationd'unepropritd'unobjet

Copyright2017Zenika.Allrightsreserved 87
Les Pipes - impure

ExcutchaquecycledusystmedeChangeDetection

PourdfinirunPipeimpure,mettrelapropritpurefalse
@Pipe({
name: 'myImpurePipe',
pure: false
})
class MyImpurePipe {
transform(value){ ... }
}

Copyright2017Zenika.Allrightsreserved 88
Les Pipes - AsyncPipe

Exempledepipeimpure

PiperecevantunePromiseouunObservableenentre

Retourneraladonnemise
@Component({
selector: 'pipes',
template: '{{ promise | async }}'
})
class PipesAppComponent {
promise: Promise;

constructor() {
this.promise = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve("Hey, this is the result of the promise");
}, 2000);
});
}
}

Copyright2017Zenika.Allrightsreserved 89
Les Pipes - Tests

InstanciationduPipedansunemthodeBeforeEach

Appeldelamthodetransformpourtestertouslescaspossibles
import {MyLowerCasePipe} from './app/mylowercase';

describe('MyLowerCasePipe', () => {
let pipe;

beforeEach(() => { pipe = new MyLowerCasePipe(); });

describe('transform', () => {
it('should return uppercase', () => {
var val = pipe.transform('SOMETHING');
expect(val).toEqual('something');
});
});

});

Copyright2017Zenika.Allrightsreserved 810
Copyright2017Zenika.Allrightsreserved 811

TP6
Copyright2017Zenika.Allrightsreserved 812
Service HTTP

9
Sommaire
Rappels

Prsentation
DmarreruneapplicationAngular
Tests
Template,Directives&Composants
LesdirectivesAngular
InjectiondeDpendances
LesPipes
ServiceHTTP

Router
GestiondesFormulaires
ServersideRendering

Copyright2017Zenika.Allrightsreserved 91
Les Observables

LepatternObservablesebasesurlalibrairieRxJS

Documentationici: https://github.com/ReactiveExtensions/RxJS
Traitementdetchesasynchronessimilairesdestableaux
Permetd'avoirdestraitementsasynchronesretournantplusieursdonnes
UnObservablepeuttrecancelable
Utilisationdemthodesdrivesdelaprogrammationfonctionnelle

map,forEach,filter,...

Utilisablepourlestraitementsasynchrones:WebSocket,gestiondes
vnementsJavaScript

Copyright2017Zenika.Allrightsreserved 92
Les Observables

Toutobservablepeuttre,commeuntableau,utilispardesfonctions
classiques:

take(n)vapiocherlesnpremierslments.

map(fn)vaappliquerlafonctionfnsurchaquevnementetretourner
lersultat.

filter(predicate)laisserapasserlesseulsvnementsqui
rpondentpositivementauprdicat.
reduce(fn)appliqueralafonctionfnchaquevnementpourrduire
lefluxuneseulevaleurunique.
merge(s1, s2)fusionneralesdeuxflux.

subscribe(fn)appliqueralafonctionfnchaquevnementquelle
reoit.
debounce(ms)retarderal'excutiond'unobservable
Copyright2017Zenika.Allrightsreserved 93
Les Observables - Exemple simple

Exmplecompletd'utilisationdesObservables

getDataFromNetworketgetDateFromAnotherRequestsontdes
traitementsasynchrones
getDataFromNetwork()
.debounce(300)
.filter (rep1 => rep1 != null)
.flatMap(rep1 => getDateFromAnotherRequest(rep1))
.map(rep2 => `${rep2} transformed`)
.subscribe(value => console.log(`next => ${value}`))

Copyright2017Zenika.Allrightsreserved 94
Les Observables - Cration

ConversiondesetIntervalenObservable
import {Observable} from 'rxjs/Observable';
import {Subscriber} from 'rxjs/Subscriber';

@Component({})
export class AppComponent {

private subscriber:Subscriber;

constructor() {
let source = new Observable(observer => {
let interval = setInterval(_ => observer.next('TICK'), 1000);
return function () {
observer.complete();
clearInterval(interval);
};
});
this.subscriber = source.subscribe(v => console.log(v));
}

reset() { this.subscriber.unsubscribe(); }

} Copyright2017Zenika.Allrightsreserved 95
Les Observables dans Angular

Angularutilisecesystmed'Observablesplusieursendroits:

requtesHTTP
intractionavecunformulaire

affichagedesvuesparlerouter
ngrx:ngrx/store,ngrx/devtools,ngrx/router,...

Copyright2017Zenika.Allrightsreserved 96
In Memory API

L'quiped'Angularproposelemoduleangular2inmemoryapipour
commencerintgreruneAPIsansserveur

sebasesuruneimplmentationinmemoryduserviceXHRBackend

idalpourcommencerlesdveloppements
npm install --save angular2-in-memory-web-api

Ncessitd'implmenterl'interfaceInMemoryDbService

Surchargerdanslesystmed'InjectiondeDpendancesl'implmentationde
XHRBackendutiliser

Copyright2017Zenika.Allrightsreserved 97
In Memory API

Exempled'utilisation:

Implmentationdel'interfaceInMemoryDbService
import { InMemoryDbService } from 'angular2-in-memory-web-api'

//API accessible via app/heroes


export class HeroData implements InMemoryDbService{
createDb() {
let heroes = [
{ id: '1', name: 'Windstorm' },
{ id: '2', name: 'Tornado' }
];
//return {heroes: heroes};
return {heroes};
}
}

Copyright2017Zenika.Allrightsreserved 98
In Memory API

Exempled'utilisation:

EnregistrementdenotreInMemoryDbService

Utilisationdel'implmentationInMemoryBackendServicepour
l'interfaceXHRBackend
import { XHRBackend } from '@angular/http';
import { InMemoryBackendService, SEED_DATA } from 'angular2-in-memory-web-api';
import { HeroData } from './hero-data';

@NgModule({
providers: [
{ provide: XHRBackend, useClass: InMemoryBackendService }, // in-mem server
{ provide: SEED_DATA, useClass: HeroData } // in-mem server
data
],
})
export class AppModule { }

Copyright2017Zenika.Allrightsreserved 99
HTTP

Angularfournitunensembledeservicespourpouvoircommuniquerviades
requtesAJAX

ServicessontdisponiblesvialemoduleHttpModulequenousdevons
importerdansnotremoduleapplicatif.
SebasesurlepatternObservablecontrairementAngularJSetses
Promises

PlusgrandeflexibilitgrceauxdiffrentsoprateursdeRxJS:retry,
...
NousinjecteronsleserviceHttppourenvoyernosrequtesHTTP

D'autresprovidersdisponibles:RequestOptionssimilaire
transformRequestd'AngularJS

Bonnepratique:implmenterlesappelsRESTdansdesservices

Copyright2017Zenika.Allrightsreserved 910
HTTP

Exemplesimpled'unserviceutilisantHttp

Importd'Httpdepuislemodule@angular/http

Injectionduservicevialeconstructeur

LamthodeduserviceretourneralersultatdelarequteHTTP
import {Http} from '@angular/http';
import {Injectable} from '@angular/core';

@Injectable()
export class HttpService {
constructor(private http:Http){ }

getContacts() {
return this.http.get('people.json');
}
}

Copyright2017Zenika.Allrightsreserved 911
HTTP - Conguration

LarequteHTTPpourratreconfigureviaunobjet
RequestOptionsArgs

PossibilitdedfinirlamthodeHTTPutilise,lesheaders,lecorpsdela
requte...
Structuredel'interfaceRequestOptionsArgs:
url : string
method : string | RequestMethod
search : string | URLSearchParams
headers : Headers
body : string

RequestMethod:enumaveclesdiffrentsmthodesHTTPpossibles

Headers:correspondlaspcificationfetch

Copyright2017Zenika.Allrightsreserved 912
HTTP - Exemple

RequteHTTPdetypePUTavecsurchargedesHeaders
import {Http, Headers} from '@angular/http';

export class HttpService {


constructor(private http:Http){ }

save(contact){
let headers = new Headers();
headers.set('Authorization', 'xxxxxxx');

return this.http.put('rest/contacts/' + contact.id, contact, {headers:


headers});
}
}

Copyright2017Zenika.Allrightsreserved 913
HTTP - Exemple

Exemplesimpled'unerequteHTTP
import {Http, Response} from '@angular/http';
import {Component} from '@angular/core';
import 'rxjs/add/operator/map';

@Component({selector: 'app', template: '{{displayedData}}'})


export class AppComponent {
private displayedData;

constructor(private http:Http) {
http.get('people.json')
.map((result:Response) => result.json())
.subscribe(jsonObject => {
this.displayedData = jsonObject;
});
}
}

Copyright2017Zenika.Allrightsreserved 914
HTTP - Exemple

Exempled'unObservableutilisantlamthodefilter
import 'rxjs/add/operator/map';
import {MyObject} from './MyObject';
import {Http, Response} from '@angular/http';
import {Component} from '@angular/core';

@Component({selector: 'app',template: '{{displayedData | json}}'})


export class AppComponent {
private displayedData = [];

constructor(private http:Http) {
http.get('people.json')
.map((result:Response) => result.json())
.filter(data => data.hasToBeDisplayed)
.map(data => new MyObject(data.id, data.name))
.subscribe((jsonObject:MyObject) => {
this.displayedData.push(jsonObject);
});
}
}

Copyright2017Zenika.Allrightsreserved 915
HTTP - Surcharger les en-ttes

PossibilitdesurchargerlesparamtresHTTPpardfaut

grcel'injectiondedpendances,utilisationdutoken
RequestOptions

tokenutilisdansleconstructeurduserviceHttp

utilisationdelaclasseBaseRequestOptionspourbnficierdes
paramtrespardfautdfinisparAngular
import {provide} from '@angular/core';
import {Http, BaseRequestOptions, RequestOptions} from '@angular/http';

class MyOptions extends BaseRequestOptions {


search: string = 'coreTeam=true';
}

@NgModule({
providers: [{provide: RequestOptions, useClass: MyOptions}],
})
export class AppModule { }
Copyright2017Zenika.Allrightsreserved 916
HTTP - Tests

PossibilitdedfiniruneimplmentationbouchonneduserviceHttp
import {TestBed, inject} from '@angular/core/testing';
import {Http, RequestOptions, Response, ResponseOptions} from '@angular/http';
import {MockBackend} from '@angular/http/testing';
import 'rxjs/add/operator/map';

describe('UserService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
UserService,
MockBackend,
BaseRequestOptions,
{
provide: Http,
useFactory: (backend: MockBackend, defaultsOptions: RequestOptions) =>
new Http(backend, defaultsOptions),
deps: [MockBackend, RequestOptions]
}
]
});
});
Copyright2017Zenika.Allrightsreserved 917
HTTP - Tests

Crationd'untestaveccetteimplmentationbouchonne
it('return return 1 user', inject([UserService, MockBackend],
(service, mockBackend) => {
let mockedUsers = [new User()];

let response = new Response(new ResponseOptions({body: mockedUsers}));

mockBackend.connections.subscribe(connection=>connection.mockRespond(response));

service.getUsers().subscribe(users => {
expect(users.length).toBe(1);
});
}));

Copyright2017Zenika.Allrightsreserved 918
Copyright2017Zenika.Allrightsreserved 919

TP7
Copyright2017Zenika.Allrightsreserved 920
Router

10
Sommaire
Rappels

Prsentation
DmarreruneapplicationAngular
Tests
Template,Directives&Composants
LesdirectivesAngular
InjectiondeDpendances
LesPipes
ServiceHTTP

Router
GestiondesFormulaires
ServersideRendering

Copyright2017Zenika.Allrightsreserved 101
Router

ModuletotalementdiffrentdumodulengRoute

ngRoutetaitunmoduletropsimpliste

UnseulngViewdansl'application

Pasdevueimbrique
Dveloppementd'unnouveauRouter
Priseencomptedesdiffrentscasd'utilisation:authentification,login,
permission,...

Etudedesautressolutions:ui-router,route-recognizeret
durandal

3eimplmentationdepuisledbutdeAngular

CompatibleavecAngularJSetAngular
Permetdefaciliterlamigrationd'uneapplicationAngularJSversAngular
Copyright2017Zenika.Allrightsreserved 102
Router

Routerorientcomposant

Associationd'uncomposantprincipalavecuneURLdevotreapplication
Utilisationd'unemthodeRouterModule.forRootpourdfinirla
configuration

UtilisationdeladirectiveRouterOutletpourdfinirlepointd'insertion

NavigationentrelespagesvialadirectiveRouterLink

InstallationviaNPM:npm install --save @angular/router


import { RouterModule } from '@angular/router';

@NgModule({
imports: [RouterModule],
})
export class AppModule { }

Copyright2017Zenika.Allrightsreserved 103
Router - forRoot

Mthodepermettantd'enregistrerdenouvellesroutes

ElleprendenparamtreuntableaudeRouterConfig,quicorrespondun
tableaudeRoute
import { RouterModule, Routes } from '@angular/router';

export const routes: Routes = [


{ path: '', component: HomeComponent }, // path: '/'
{ path: 'contacts', component: ContactsComponent },
{ path: 'contact/:id', component: ContactComponent }
];

@NgModule({
imports: [
RouterModule.forRoot(routes)
],
})
export class AppModule { }

Copyright2017Zenika.Allrightsreserved 104
Router - RouterOutlet

Directiveutiliservial'attributrouter-outlet

Permetdedfinirlepointd'insertiondanslecomposantprincipal
Lecomposantserainsrentantqu'enfantdel'lmentsurlequella
directiveRouterOutletestutilise

Possibilitdedfinirlavueviaunattributname(utilispourdfinirplusieurs
vuesaummeniveau)
Possibilitdecrerdesvuesenfantgrcel'utilisationdeRouterOutlet
imbriques
@Directive({selector: 'router-outlet'})
export class RouterOutlet {
constructor(
private _elementRef: ElementRef,
private _loader: DynamicComponentLoader,
private _parentRouter: routerMod.Router,
@Attribute('name') nameAttr: string) {...}
}
Copyright2017Zenika.Allrightsreserved 105
Router - RouterOutlet

ExemplesimpledeladirectiveRouterOutlet
import { Component } from '@angular/core';

@Component({
template: '
<header><h1>Title</h1></header>
<router-outlet></router-outlet>
'
})
class AppComponent { }

Copyright2017Zenika.Allrightsreserved 106
Router - RouterLink

Permetdenaviguerd'unerouteuneautre

UtilisationdelamthodenavigateduserviceRouter

LadirectiveRouterLinks'attenduntableaudenomsderoutes,suivipar
d'ventuelsparamtres
@Component({
template: '
<div>
<h1>Hello {{message}}!</h1>
<a [routerLink]="['contacts']">Link 1</a>
<a [routerLink]="['contact', 1]">Link 2</a>
<router-outlet></router-outlet>
</div>'
})
class AppComponent {

Copyright2017Zenika.Allrightsreserved 107
Router - RouterOutlet imbriques

ImbricationdeplusieursRouterOutletpourdfinirunehirarchiedevues
import { RouterModule, RouterConfig } from '@angular/router';
import { HeroListComponent } from './hero-list.component';
import { HeroDetailComponent } from './hero-detail.component';

export const routes = [


{ path: 'contact/:id', component: ContactComponent, children: [
{path: 'edit', component: EditCmp},
{path: 'view', component: ViewCmp}
]},
{ path: 'contacts', component: ContactsComponent }
];

const routing = RouterModule.forRoot(routes);

Copyright2017Zenika.Allrightsreserved 108
Router - RouterLink en dtails

UtilisationviaunattributrouterLink

ConfigurationdelaroutedsireviacemmeattributrouterLink

AttributhrefgnrparleserviceLocation

AjoutdeclassesCSSsilarouteestactive(directiverouterLinkActive)
@Directive({selector: '[routerLink]'})
export class RouterLink implements OnChanges {
@Input() routerLink: any[]|string;
@HostBinding() href: string;

ngOnChanges(changes: {}): any { this.updateTargetUrlAndHref(); }

@HostListener('click', [])
onClick(): boolean {
...
this.router.navigateByUrl(this.urlTree);
return false;
}
}
Copyright2017Zenika.Allrightsreserved 109
Router - Stratgies pour le gnration des URLs

PathLocationStrategy(stratgiepardfaut)

Ncessiteladfinitiondel'URLdebasedevotreapplication
(APP_BASE_HREFou<base>)
router.navigate(['contacts']); //example.com/my/app/contacts

HashLocationStrategy
router.navigate(['contacts']); //example.com#/contacts

Possibledeconfigurerl'implmentationutiliser
import {HashLocationStrategy, LocationStrategy } from '@angular/common';

@NgModule({
providers: [{ provide: LocationStrategy, useClass: HashLocationStrategy }],
})
export class AppModule { }

Copyright2017Zenika.Allrightsreserved 1010
Router - Conguration de l'URL de base de
l'application

Dfinitiond'unnouveauproviderpourlaconstanteAPP_BASE_HREF

SerautilislorsdelagnrationdesdiffrentesURLS
import {Component} from '@angular/core';
import {APP_BASE_HREF} from '@angular/common';

@NgModule({
providers: [{ provide: APP_BASE_HREF, useValue: '/my/app' }],
})
export class AppModule { }

Copyright2017Zenika.Allrightsreserved 1011
Router - Rcupration des paramtres d'URL

UtilisationduserviceActivatedRouteetparams(Observable)
@Component({
template: '
<a [routerLink]="['contact', 1]"></a>
<router-outlet></router-outlet>'
})
class AppComponent { }

import { ActivatedRoute } from '@angular/router';

@Component({
template: '<main><router-outlet></router-outlet></main>'
})
export class ProductComponent {
constructor(private _route: ActivatedRoute) {}

ngOnInit() {
this._route.params.subscribe(params => {
let id = +params['id']; // (+) conversion 'id' string en number
...
});
}
} Copyright2017Zenika.Allrightsreserved 1012
Router - Rcupration des paramtres d'URL

UtilisationduserviceActivatedRouteetsnapshot
@Component({
template: '
<a [routerLink]="['contact', 1]"></a>
<router-outlet></router-outlet>'
})
class AppComponent { }

import { ActivatedRoute, ActivatedRouteSnapshot } from '@angular/router';

@Component({
template: '<main><router-outlet></router-outlet></main>'
})
export class ProductComponent {
constructor(private _route: ActivatedRoute) {}

ngOnInit() {
const s: ActivatedRouteSnapshot = this._route.snapshot;
// Valeur initiale des paramtres
let id = +s.params.id;
...
}
} Copyright2017Zenika.Allrightsreserved 1013
Router - Cycle de Vie

Possibilitd'intragiraveclecycledeviedelanavigation(LifecycleHooks)

InterfaceCanActivate:interdire/autoriserl'accsuneroute
import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot } from '@angular/router';
import { AuthService } from '../shared/auth.service';

@Injectable()
export class AuthGuard implements CanActivate {
constructor(private _authService: AuthService, private router: Router) {}
canActivate(route: ActivatedRouteSnapshot) {
if(this._authService.isLoggedIn()) return true;
this.router.navigate(['/login']);
return false;
}
}

// fichier app/application.routes.ts
import { AdminComponent, AuthGuard } from './admin/';
export const AppRoutes: RouterConfig = [
{ path: 'admin', component: AdminComponent, canActivate: [AuthGuard] }
];
Copyright2017Zenika.Allrightsreserved 1014
Copyright2017Zenika.Allrightsreserved 1015

TP8
Copyright2017Zenika.Allrightsreserved 1016
Gestion des
Formulaires

11
Sommaire
Rappels

Prsentation
DmarreruneapplicationAngular
Tests
Template,Directives&Composants
LesdirectivesAngular
InjectiondeDpendances
LesPipes
ServiceHTTP

Router
GestiondesFormulaires
ServersideRendering

Copyright2017Zenika.Allrightsreserved 111
Formulaires et Angular

SebasesurlesmcanismesstandardsdesformulairesHTML

Supportelestypesdechampsdesaisiehabituelsetlesvalidationsnatives
input[text],input[radio],input[checkbox],input[email],
input[number],input[url]

select

textarea

Ilestpossibledecrersesproprescomposants

Copyright2017Zenika.Allrightsreserved 112
Formulaires : Principe gnral

Associerdeschampsdesaisiedespropritsducomposantgrce
ngModel

Nommerleschampsgrcel'attributname

Ajouterdesvalidateurs

AppelerunemthodeducomposantpourtraiterleformulaireenJavaScript

Copyright2017Zenika.Allrightsreserved 113
NgForm
LadirectiveNgFormestautomatiquementassociechaquebalise<form>

Autorisel'utilisationdu(ngSubmit)

CreunFormGrouppourgrerlesinputscontenusdansleformulaire

Utilisableparl'criture:#myForm="ngForm"
<form #myForm="ngForm">
<!-- disabled button if form is invalid -->
<button type="submit" [disabled]="!myForm.valid">Save</button>
</form>

Copyright2017Zenika.Allrightsreserved 114
Directives

ngModel:GrelebindingentrelavariableducontrleuretlechampHTML
<input type="text" [(ngModel)]="contact.name" name="name">

submit:Associeunemthodelasoumissionduformulaire
<form (submit)="saveForm()">
<button type="submit">Save</button>
</form>

Copyright2017Zenika.Allrightsreserved 115
Validation : Dsactiver la gestion native

Pardfaut,lesnavigateurseffectuentlesvalidationsnativement

Manquedecohrencevisuelleavecl'applicationetentrenavigateurs
Interfreaveclemcanismed'AngularJs

Solution:Dsactiverlavalidationnativeetl'effectuerparAngular
Attributnovalidatesurleformulaire

AttributstandardHTML5

AttributajoutautomatiquementparAngular
<form novalidate>
</form>

Copyright2017Zenika.Allrightsreserved 116
FormControl

UnFormControlestuneclassereprsentantuninputquicontient:

Lavaleur
L'tat(dirty,valid,...)

Leserreursdevalidation
AngularcreunFormControldsl'utilisationdeladirectivengModel

Ilutiliselavaleurdelapropritnamecommelibell

Onpeutl'associerunevariablepourl'utiliserdansletemplateavecla
syntaxe#inputName="ngModel"

Copyright2017Zenika.Allrightsreserved 117
Exemple
Exemplecomplet:
<form #myForm="ngForm" novalidate (submit)="onSubmit(myForm.value)">
<input type="text" name="myName" [(ngModel)]="contact.name"
#nameInput="ngModel" required>
<span [hidden]="nameInput.valid">Error</span>
<span [hidden]="nameInput.pristine">You changed the value</span>

<button type="submit" [disabled]="!myForm.valid">


Validate
</button>
</form>

// myForm.value -> { myName: '' }

Copyright2017Zenika.Allrightsreserved 118
Validation : Concept

Unchamppeutpossderunouplusieursvalidateurs

Standardsoupersonnaliss
SupportdesvalidateursHTML5:required,min,max,...

L'tatdelavalidationeststockparl'objetFormControldanslaproprit
errors
<input type="text" [(ngModel)]="contact.name" #name="ngModel" name="name"
required>
<span [hidden]="!name.errors?.required">Name is not valid</span>

Copyright2017Zenika.Allrightsreserved 119
Validation : tat du formulaire et des champs

Angularexpose5propritsauniveauduformulaireetdechacundes
champsdesaisie

valid/invalid:Indiquesil'lmentpasselecontrledesvalidateurs

pristine/dirty:Indiquentsil'utilisateuraaltrl'lment

Unlmentestconsidrdirtydsqu'ilsubitunemodification,
mmesilavaleurinitialeestrestaureensuite
untouched/touched:Indiquentsil'lmentattouch(focus)

LesclassesCSScorrespondantessontappliquesauxlments(viala
directiveNgControlStatus)

ng-valid,ng-invalid,ng-pristine,ng-dirty,ng-untouched,
ng-touched

Copyright2017Zenika.Allrightsreserved 1110
Validation : Cration d'un validateur
Ilestpossibledecrersespropresvalidateursavecuneclasseimplmentant
l'interfaceValidator
@Directive({
selector: '[pattern][ngModel]',
providers: [
{ provide: NG_VALIDATORS, useExisting: PatternValidator, multi: true }
]
})
export class PatternValidator implements Validator {
@Input('pattern') pattern: string;

validate(c: AbstractControl): { [key: string]: any } {


if (c.value && c.value.match(new RegExp(this.pattern))) {
return null;
}
return { pattern: true };
}
}

<input type="text" name="name" [(ngModel)]="contact.name" pattern="[a-z]{10}">

Copyright2017Zenika.Allrightsreserved 1111
Copyright2017Zenika.Allrightsreserved 1112

TP9
Copyright2017Zenika.Allrightsreserved 1113
Server-side Rendering

12
Sommaire
Rappels

Prsentation
DmarreruneapplicationAngular
Tests
Template,Directives&Composants
LesdirectivesAngular
InjectiondeDpendances
LesPipes
ServiceHTTP

Router
GestiondesFormulaires
ServersideRendering

Copyright2017Zenika.Allrightsreserved 121
Besoin

Indexationparlesmoteursderecherche(SEO)

Prvisualisation(commedanslepartagefacebook)
Amliorationprogressive

Proposeruneversionsimplepourtous
Enrichirl'exprienceenfonctionduclient
Acclrerlechargementdel'application

Copyright2017Zenika.Allrightsreserved 122
Angular Universal

ProjetAngularofficiel.ContrairementauxprojetsdeServerSideRendering
pourAngularJS

Contientdeuxmodules
Lepremierrendlecodectserveur

Ledeuximeenregistrelesactionsdel'utilisateurpourlesrejouerune
foisl'interfacecompltementcharge
LetermeUniversalvientdel'idedepouvoirproposerl'applicationdans
d'autresenvironnementsqueceluidunavigateur
Pasencoreassezstablepourlamiseenproduction

Copyright2017Zenika.Allrightsreserved 123
Mchanisme

AngularJSfortementliauDOM

Angularintroduitunesparationdumcanismederendu

Copyright2017Zenika.Allrightsreserved 124
Procdure de rendu

Lemoteurderendu(ExpressenNodeJS)vaconstruireleHTML

LepluginAngular Universalvaraliserlebootstrapdel'application

LarponsedesappelsRESTestattendue

Lapagecompltementconstruiteestretournl'utilisateur
LalibrairiePrebootdeAngular Universalenregistrelesactionsde
l'utilisateur
Lenavigateurclientterminedechargerlecodejavascript

LalibrairiePrebootrejouelesactionsdel'utilisateur

Copyright2017Zenika.Allrightsreserved 125
Mise en place

Leplussimpleestdereprendrelestarter
https://github.com/angular/universalstarter

Crerdeuxpointsd'entrespourl'application
Classiquepourleclientaveclafonctionbootstrap

PourleserveuraveclamiseenplacedeExpressetdeAngular
Universal

Copyright2017Zenika.Allrightsreserved 126
Rendu serveur
Elementsnotablesduscriptdelancementduserveur
import 'angular2-universal-polyfills';
import { createEngine, ExpressEngineConfig } from 'angular2-express-engine';
import { MainModule } from './main.node';

app.engine('.html', createEngine({}));

app.get('/*', (req, res) => {

const expressConfig : ExpressEngineConfig = {


req,
res,
ngModule: MainModule,
preboot: false,
};
res.render('index', expressConfig);
});

Copyright2017Zenika.Allrightsreserved 127
Copyright2017Zenika.Allrightsreserved 128