Documente Academic
Documente Profesional
Documente Cultură
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;
Copyright2017Zenika.Allrightsreserved 15
Fonctions
CommeenJavaScript,possibilitdecrerdesfonctionsnommesou
anonymes
//Fonction nomme
function namedFunction():void { }
//Fonction anonyme
let variableAnonymousFunction = function(): void { }
Peutretournerunevaleurgrceaumotclreturn
Accsauxvariablesdfiniesendehorsduscopedelafonction
let externalScope:number = 10;
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 };
Lavaleurnumriquecommencepardfaut0
Possibilitdesurchargerlesvaleursnumriques
enum Music { Rock = 2, Jazz = 4, Blues = 8 };
Rcuprationdelachanedecaractresassocielavaleurnumrique
let style: string = Music[4]; //Jazz
Copyright2017Zenika.Allrightsreserved 19
Classes
Systmedeclassesetinterfacessimilairelaprogrammationoriente
objet
Lecodejavascriptgnrutiliseralesystmedeprototype
Possibilitdedfinirunconstructeur,desmthodesetdesproprits
Proprits/mthodesacccessiblesvial'objetthis
class Person {
constructor() {}
}
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;
}
}
Systmed'hritageentreclassesvialemotclextends
Siconstructeurnondfini,excuteceluidelaclasseparente
Possibilitd'appelerl'implmentationdelaclasseparenteviasuper
Accsauxpropritsdelaclasseparentesipublicouprotected
class Person {
constructor() {}
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;
}
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);
}
}
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
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
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']}),
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;
});
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() {
Copyright2017Zenika.Allrightsreserved 46
Tests - Tests TypeScript
Possibilitd'criredestestsenTypeScript
class True {
returnTrue(){ return 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
<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';
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>();
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';
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']"
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;
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>> 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] });
});
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;
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'
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';
save(contact){
let headers = new Headers();
headers.set('Authorization', 'xxxxxxx');
Copyright2017Zenika.Allrightsreserved 913
HTTP - Exemple
Exemplesimpled'unerequteHTTP
import {Http, Response} from '@angular/http';
import {Component} from '@angular/core';
import 'rxjs/add/operator/map';
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';
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';
@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()];
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
@NgModule({
imports: [RouterModule],
})
export class AppModule { }
Copyright2017Zenika.Allrightsreserved 103
Router - forRoot
Mthodepermettantd'enregistrerdenouvellesroutes
ElleprendenparamtreuntableaudeRouterConfig,quicorrespondun
tableaudeRoute
import { RouterModule, Routes } from '@angular/router';
@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';
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;
@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 { }
@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 { }
@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>
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;
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({}));
Copyright2017Zenika.Allrightsreserved 127
Copyright2017Zenika.Allrightsreserved 128