50
1 Angular 2 ROMAGNY13 Table des matières 1. EDI ............................................................................................................................ 4 2. TypeScript ................................................................................................................. 4 3. Création de projet ..................................................................................................... 4 a. En suivant le guide avec Webpack/ téléchargeant un starter-kit............................ 4 b. Avec Angular CLI ................................................................................................... 5 « angular-cli.json »..................................................................................................... 6 Génération de code ................................................................................................... 6 c. Quickstart avec System.js....................................................................................... 8 4. Liens utiles ................................................................................................................ 8 5. Module Angular......................................................................................................... 9 6. Component ..............................................................................................................10 a. Styles ....................................................................................................................11 b. ViewEncapsulation................................................................................................11 c. Lifecyle hooks .......................................................................................................12 d. Relative paths (uniquement avec System.js) ..........................................................12 7. Binding .....................................................................................................................12 a. String interpolations..............................................................................................13 a. Property binding...................................................................................................13 b. Event binding .......................................................................................................14 c. Two way binding...................................................................................................15 d. Nested component ................................................................................................15 e. Local reference .....................................................................................................17 8. Directives .................................................................................................................17 a. Attribute directives ...............................................................................................17 ngClass ....................................................................................................................17 ngStyle .....................................................................................................................17 b. Structural directives ..............................................................................................17 ngIf ...........................................................................................................................17 ngSwitch ...................................................................................................................18 ngFor........................................................................................................................18 9. Pipes (« équivalent » des filtres d’Angular 1) ............................................................19 a. Async pipe ............................................................................................................19

1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

  • Upload
    others

  • View
    4

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

1

Angular 2 ROMAGNY13

Table des matières 1. EDI ............................................................................................................................ 4

2. TypeScript ................................................................................................................. 4

3. Création de projet ..................................................................................................... 4

a. En suivant le guide avec Webpack/ téléchargeant un starter-kit ............................ 4

b. Avec Angular CLI ................................................................................................... 5

« angular-cli.json » ..................................................................................................... 6

Génération de code ................................................................................................... 6

c. Quickstart avec System.js ....................................................................................... 8

4. Liens utiles ................................................................................................................ 8

5. Module Angular ......................................................................................................... 9

6. Component .............................................................................................................. 10

a. Styles .................................................................................................................... 11

b. ViewEncapsulation ................................................................................................ 11

c. Lifecyle hooks ....................................................................................................... 12

d. Relative paths (uniquement avec System.js) .......................................................... 12

7. Binding ..................................................................................................................... 12

a. String interpolations .............................................................................................. 13

a. Property binding ................................................................................................... 13

b. Event binding ....................................................................................................... 14

c. Two way binding ................................................................................................... 15

d. Nested component ................................................................................................ 15

e. Local reference ..................................................................................................... 17

8. Directives ................................................................................................................. 17

a. Attribute directives ............................................................................................... 17

ngClass .................................................................................................................... 17

ngStyle ..................................................................................................................... 17

b. Structural directives .............................................................................................. 17

ngIf ........................................................................................................................... 17

ngSwitch ................................................................................................................... 18

ngFor ........................................................................................................................ 18

9. Pipes (« équivalent » des filtres d’Angular 1) ............................................................ 19

a. Async pipe ............................................................................................................ 19

Page 2: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

2

b. Custom pipe ......................................................................................................... 20

c. Autre exemple : Filtre ........................................................................................... 20

10. Debug (avec sourceMap) ...................................................................................... 21

Augury ......................................................................................................................... 21

11. Routing & navigation ............................................................................................. 22

a. Au plus simple ...................................................................................................... 22

b. Location stratégies ................................................................................................ 23

c. Passage de paramètre ........................................................................................... 23

d. Navigation par programmation ............................................................................. 24

e. Autres paramètres de routes ................................................................................. 24

f. Préserver les query params/ fragment quand on navigue vers une autre url ........ 26

g. Redirection ........................................................................................................... 26

h. Child routes .......................................................................................................... 26

i. RouterLinkActive ................................................................................................... 27

j. Route guards ......................................................................................................... 27

k. Mieux organiser ses routes ................................................................................... 28

l. Créer des modules pour le routing ....................................................................... 30

m. Lazy loading ...................................................................................................... 32

n. PreloadinStrategy ................................................................................................. 33

12. Services ................................................................................................................ 33

a. Dependency injection ........................................................................................... 33

b. http ....................................................................................................................... 34

Avec Observable...................................................................................................... 34

CRUD ....................................................................................................................... 36

Async pipe ............................................................................................................... 37

Avec promise ........................................................................................................... 37

13. Mean ..................................................................................................................... 38

14. Firebase ................................................................................................................ 40

15. Forms .................................................................................................................... 43

a. Template driven .................................................................................................... 43

b. Reactive forms ...................................................................................................... 44

16. Animations ............................................................................................................ 46

17. Test ....................................................................................................................... 46

a. Test de service ...................................................................................................... 46

b. Test de service http ............................................................................................... 47

c. Tester un component avec injection ...................................................................... 48

18. AOT (AHEAD-OF-TIME COMPILATION) ................................................................ 50

Page 3: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

3

19. Déploiement ......................................................................................................... 50

20. Migration .............................................................................................................. 50

Upgrade d’un projet Angular 2 fait avec une ancienne version d’Angular Cli vers

Angular Cli 1.0.0 .......................................................................................................... 50

Site, Quickstart

Page 4: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

4

1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être utile si on n’utilise pas les

commandes Angular-Cli) de J. Papa

WebStorm

2. TypeScript Angular 2 repose sur TypeScript. Ce document se concentre sur Angular 2. Quelques

bons liens quand même. En cours, on peut regarder du côté de Udemy, Pluralsight,

Egghead. La documentation officielle n’est pas forcément bien faite (la création de

fichiers de définition par exemple), il faudra parfois aller chercher les informations dans

les notes de mises à jour.

TypeScript permet notamment un typage fort. C’est un vrai apport par rapport à l’es6. Il

ne se contente bien entendu pas que de cela. Le code généré est également assez

propre.

Ici pas question de transpiler directement le TypeScript, on passera par l’intermédiaire

de Webpack. On peut utiliser un starter-kit ou Angular-Cli pour éviter de refaire la

configuration à chaque fois.

3. Création de projet

a. En suivant le guide avec Webpack/ téléchargeant un starter-kit Guide d'installation avec Webpack, NPM Packages

Starter kit avec Webpack (résultat du guide)

Installation des dépendances

npm i

Tests avec Jasmine

npm test Lancer le serveur de développement

npm start

… Se rendre à http://localhost:8080/

Build (avec Webpack)

npm run build

Seed project

Page 5: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

5

b. Avec Angular CLI Site, github, référence, quickstart

Installation

npm i angular-cli -g

Ou pour avoir la dernière version

npm i angular-cli@latest -g

Création d’un projet

ng new <project-name> [options]

Options intéressantes : prefix (utilisé pour les components) exemple « --prefix abc » ce

qui donnerait en selector « abc-product-list »

Lancer le serveur de developpement

cd project-name

ng serve <project-name>

… Se rendre à « http://localhost:4200/ »

En cas de problème

Si une dépendance semble manquer, faire un « npm i »

Si on désire réinstaller carrément Angular-cli avec la dernière version

npm uninstall -g angular-cli

npm cache clean

npm install -g angular-cli@latest

Commandes

Aide : wiki,référence ,github du projet et commande :

ng help

Page 6: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

6

Lint

ng lint

Tests (unitaires)

ng test [options]

E2e

ng e2e

Build (dossier « dist »)

ng build

ng build -prod

« angular-cli.json » On peut éditer directement le fichier de configuration d’Angular-Cli (à la racine du

porjet) et par exemple changer le préfixe par défaut des components

On peut également ajouter des styles (exemple avec Boostrap)

Note il y a quand même des Scripts NPM (se contentent de faire le lien avec les

commandes d’Angular-Cli)

npm start

npm test

npm e2e

Génération de code

wiki

ng g <type> [options]

Types valides :

module (ou m)

component (ou c)

directive

route

pipe

service (ou s)

class

interface

enum

Page 7: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

7

Module Au plus simple

ng g m products

Note : le module n’est pas ajouté à AppModule, l’ajouter si pas de lazy loading

Options :

--spec true génére fichier de tests

--routing true

ng g m products --routing true

Component Au plus simple

ng g c products

Options

-it inline template

-is inline style

--flat pas de sous dossier crée pour le component

--spec false ne génére pas le fichier de tests du component

--prefix préfixe à utiliser

-ve ViewEncapsulation strategy

-cd change detection strategy

--skip-import

ng g c products/products -it -is --flat --spec false

Routing généré (forChild)

pour le module

Component avec « router-outlet »

Module

Page 8: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

8

Exemple 2 : Component dans un sous dossier

ng g c products/product-list

Service

ng g s products/product

Ajouter le service aux providers du module

Options :

--spec false ne génére pas le fichier de tests du component

c. Quickstart avec System.js lien

4. Liens utiles Guide de bonnes pratiques (Style guide)

Cheat sheet

Observables rxjs, introduction rxjs, intro avec Angular

Getting started demos (J. Papa)

Deborah Kurata github (demos sur Angular 2, Reactive forms, etc.)

Pour créer des applications de démos :

mLab : création de base MongoDB (500mb free). Créer un compte, puis créer un

déploiement « single-node » « Sandbox »

Api :

Github : affichage des users et repositories. Créer une app OAuth (documentation)

Movies : créer un compte (documentation), OMDb API

Spotify : créer un compte (documentation)

Weather

Page 9: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

9

5. Module Angular Documentation, faq

Un module Angular à la base c’est une classe avec un decorator « NgModule » :

import { NgModule } from '@angular/core';

@NgModule({

imports: [],

declarations: []

})

export class ProductModule { }

Un module peut avoir :

- imports (modules) Modules utilisés par ce module (exemple CommonModule pour les

directives ngIf, HttpModule pour des requêtes http, etc.)

- déclarations (components, directives et pipes). Par défaut les components, directives

et pipes sont « privés », accessibles seulement dans leur module

- exports (components, directives et pipes) rend les components, directives et pipes

exportés accessibles aux autres modules qui importerait ce même module.

- providers (services) : permettent d’enregistrer les services avec l’injector, ce qui les

rend disponible à toute l’application

Root application module (AppModule) :

peut être le seul module pour les petites applications

boostrap le root application component (AppComponent)

Exemple :

import { BrowserModule } from '@angular/platform-browser';

import { NgModule } from '@angular/core';

import { FormsModule } from '@angular/forms';

import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';

@NgModule({

declarations: [

AppComponent

],

imports: [

BrowserModule,

FormsModule,

HttpModule

],

providers: [],

bootstrap: [AppComponent]

})

export class AppModule { }

Note : browserModule ne doit être utilisé qu’une fois (AppModule). Utiliser

CommonModule pour les autres modules.

Feature module (exemple un module « product ») : permet de mieux structurer

l’application (separation of concerns)

Shared module : déclarations (components, pipes et directives) + exports (modules

CommonModule , FormsModule par exemple) partagés (pas de providers, faire un core

Bootstrap AppComponent

AppComponent ajouté au tableau de

déclarations

Modules utilisés

par le module

Components à ajouter en

déclarations

Page 10: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

10

module pour cela). Le module est déclaré dans les imports de « AppModule », ce qui

permet de partager les éléments à toute l’application.

Core module : services (providers) (et components) chargés (une seule fois) à

l’initialisation de l’application.

Route modules : permettent de structurer le routing.

6. Component Un component c’est une classe (properties + methods) avec un decorator @Component

(metadata) permettant de définir le template/ template url, etc.

Note : une bonne pratique consiste à préfixer les selectors des components (exemple

avec « app » ce qui donne « app-product-list ») pour éviter les éventuels conflits

import { Component, OnInit } from '@angular/core';

@Component({

selector: 'app-product-list',

templateUrl: './product-list.component.html'

})

export class ProductListComponent implements OnInit {

constructor() { }

ngOnInit() {

}

}

Avec les template on peut utiliser les backticks

import { Component, OnInit } from '@angular/core';

@Component({

selector: 'app-product-list',

template: `<h1>Title</h1>

<p>Content.</P>`

})

export class ProductListComponent implements OnInit {

// etc.

}

Le component doit être ajouté aux déclarations du module (AppModule ou feature

module)

import { NgModule } from '@angular/core';

import { CommonModule } from '@angular/common';

import { ProductListComponent } from './product-list/product-

list.component';

@NgModule({

imports: [

CommonModule

],

declarations: [ProductListComponent]

})

export class ProductModule { }

Page 11: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

11

a. Styles Documentation

« stylesUrls » tableau avec liens vers feuilles de styles

Ou « styles » (tableau de styles) (note : on peut utiliser les backticks pour définir dans

le tableau des styles sur plusieurs lignes)

b. ViewEncapsulation Documentation

None (styles « normaux »)

Exemple : Style ajouté dans le head

Native (shadow dom, pas supporté encore pas tous les navigateurs)

Style ajouté au component

Emulated

Style ajouté dans le « head »

Indiquée au niveau du component. Exemple

import { Component, ViewEncapsulation } from '@angular/core';

@Component({

selector: 'app-first',

template: `

<p [ngClass]="{ colorRed:true }">My text</p>

`,

encapsulation: ViewEncapsulation.Emulated,

styles: ['.colorRed { color: red }']

})

export class FirstComponent {}

Page 12: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

12

c. Lifecyle hooks Documentation

OnChanges

OnInit

DoCheck

AfterContentInit

AfterContentChecked

AfterViewInit

AfterViewChecked

onDestroy

Exemple

import { Component, OnInit } from '@angular/core';

@Component({

selector: 'app-product-list',

template: `

<h1>Title</h1>

`,

styles: []

})

export class ProductListComponent implements OnInit {

ngOnInit() {

}

}

d. Relative paths (uniquement avec System.js) Documentation

moduleId du decorator @component permet de simplifier les chemins des templates

et feuilles de styles des components.

Par exemple on pourra écrire simplement « ./first.component.html » au lieu de

« app/first.component.html »

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

@Component({

selector: 'app-first',

templateUrl:'./first.component.html'

})

export class FirstComponent {}

7. Binding

{{}} => interpolation

[] => property binding

() => event binding

« Tout JavaScript valide » exemple opérateur ternaire, appel de function, etc.

Properties

Events

Component DOM

Page 13: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

13

a. String interpolations import { Component } from '@angular/core';

@Component({

selector: 'app-first',

template: `

<h1>{{ myTitle }}</h1>

<p>{{ myNumber }}</p>

`

})

export class FirstComponent {

myTitle: string = "My title";

myNumber: Number = 10;

}

a. Property binding

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

@Component({

selector: 'app-first',

template: `

<input type="text" [value]="myTitle"/>

<img [src]="myImage" />

`

})

export class FirstComponent {

myTitle: string = "My title";

myImage = "../assets/myimage.png";

}

Equivalent avec interpolation

Avec l’attribut « class »

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

@Component({

selector: 'app-first',

template: `

<p [class.colorRed]="true">My text</p>

`,

styles: ['.colorRed { color: red }']

})

export class FirstComponent {}

<img [src]="myImage" />

HTML Element attribute

(target)

Expression (source)

Page 14: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

14

Avec l’attribut « style »

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

@Component({

selector: 'app-first',

template: `

<p [style.color]="'blue'">My text</p>

`

})

export class FirstComponent {}

b. Event binding

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

@Component({

selector: 'app-first',

template: `

<button (click)="onClick()">My button</button>

`

})

export class FirstComponent {

myTitle: string = "My title";

onClick() {

}

}

Passer l’event à la function

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

@Component({

selector: 'app-first',

template: `

<button (click)="onClick($event)">My button</button>

`

})

export class FirstComponent {

onClick(e) {

console.log(e);

}

}

Passer des données

Passer l’event + données

<button (click)="onClick()">My button</button>

Event (target) Méthode du component

Page 15: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

15

c. Two way binding import { Component } from '@angular/core';

@Component({

selector: 'app-first',

template: `

<input type="text" [(ngModel)]="person.name"/>

{{ person.name }}

<button (click)="changeName()">Change name</button>

`

})

export class FirstComponent {

person = {

name: "Marie"

};

changeName() {

this.person.name = "New Name";

}

}

Sans ngModel

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

@Component({

selector: 'app-first',

template: `

<input type="text" [value]="person.name"

(keyup)="person.name=$event.target.value"/>

`

})

export class FirstComponent {}

d. Nested component

Parent => child

Template de « AppComponent »

<div>

<app-parent></app-parent>

</div>

Parent

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

@Component({

selector: 'app-parent',

template: `

<app-child [result]="1000"></app-child>

`

})

export class ParentComponent {}

Obj => HTML Element

Parent component

Child

component Output

Input

Page 16: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

16

Child

import { Component, Input } from '@angular/core';

@Component({

selector: 'app-child',

template: `

<p>

{{ result }}

</p>

`,

styles: []

})

export class ChildComponent {

@Input() result: number = 10;

}

Affichera 1000 en sortie

(Les components parent et child sont à ajouter aux déclarations du module AppModule

pour l’exemple)

Child => parent

Child

import { Component, Output, EventEmitter } from '@angular/core';

@Component({

selector: 'app-child',

template: `

<button (click)="onClick()">Click!</button>

`

})

export class ChildComponent {

@Output() notified = new EventEmitter<string>();

onClick() {

this.notified.emit('to parent');

}

}

Parent

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

@Component({

selector: 'app-parent',

template: `

<app-child (notified)="onNotified($event)"></app-child>

`

})

export class ParentComponent {

onNotified(value: string) {

console.log('notified from child', value);

}

}

On s’abonne au custom event « notified » du

child. Lorsque l’on est notié on passe $even t (les

données (« to parent » dans l’exemple)

Page 17: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

17

e. Local reference Sur un HTML element permet de définir une référence utilisable dans le html pour du

binding direct par rapport à cet élément

8. Directives

a. Attribute directives Sont appliquées avec [] comme le property binding, c’est pour cela qu’on les appelle

« attribute » directives.

Interagissent avec l’élément HTML sur lesquelles elles sont appliquées

ngClass (Equivalent de l’exemple avec attribut « class »)

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

@Component({

selector: 'app-first',

template: `

<p [ngClass]="{ colorRed:true }">My text</p>

`,

styles: ['.colorRed { color: red }']

})

export class FirstComponent {}

ngStyle (Equivalent de l’exemple avec attribut « style »)

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

@Component({

selector: 'app-first',

template: `

<p [ngStyle]="{ color:'blue' }">My text</p>

`

})

export class FirstComponent {}

b. Structural directives Changent le HTML/ la structure du DOM

ngIf Ajoute ou non selon la condition l’élément

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

@Component({

selector: 'app-first',

template: `

<div *ngIf="switch">Affiché si le switch est vrai</div>

`

})

export class FirstComponent {

switch = true;

}

La classe css est ajoutée selon la condition

(tout JavaScript valide)

Style inline

Page 18: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

18

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

@Component({

selector: 'app-first',

template: `

<div [ngSwitch]="value">

<p *ngSwitchCase="10">10</p>

<p *ngSwitchCase="100">10</p>

<p *ngSwitchDefault>Autre</p>

</div>

`

})

export class FirstComponent {

value = 10;

}

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

@Component({

selector: 'app-first',

template: `

<ul>

<li *ngFor="let fruit of fruits">{{ fruit }}</li>

</ul>

`

})

export class FirstComponent {

fruits = ['banane', 'pêche', 'poire'];

}

Avec index

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

@Component({

selector: 'app-first',

template: `

<ul>

<li *ngFor='let fruit of fruits;let i = index'>{{ fruit }} - {{ i

}}</li>

</ul>

`

})

export class FirstComponent {

fruits = ['banane', 'pêche', 'poire'];

}

Page 19: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

19

9. Pipes (« équivalent » des filtres d’Angular 1) Documentation

Permettent de transformer les données affichées

Built-in pipes :

uppercase

lowercase

date[ :format]

number[ :format]

async (subscribe à une promise ou un observable)

json

etc.

Exemple

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

@Component({

selector: 'app-first',

template: `

<div>

<h1>{{ title | uppercase }}</h1>

</div>

`

})

export class FirstComponent {

title: string = "My title";

}

On peut enchainer plusieurs pipes

{{ price | currency | lowercase }}

… et avoir des paramètres

{{ birthday | date:"MM/dd/yy" }}

{{ price | currency:'USD':true:'1.2-2' }}

a. Async pipe import { Component } from '@angular/core';

@Component({

selector: 'app-product-list',

template: `

<div>

<h1>{{ title | async }}</h1>

</div>

`

Min digits puis min fraction digits et enfin

max fraction digits

Page 20: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

20

})

export class ProductListComponent {

title = new Promise((resolve) => {

setTimeout(() => resolve('product list'), 2000);

});

}

b. Custom pipe On peut générer facilement le code de base avec Angular-Cli (exemple avec une pipe

permet de mettre en capitale la première lettre d’une chaine de caractères nommée

« capitalize »)

ng g pipe capitalize

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({

name: 'capitalize'

})

export class CapitalizePipe implements PipeTransform {

transform(value: any, args?: any): any {

return value.toLowerCase().replace(/^[a-z]/, (f) => f.toUpperCase());

}

}

Ajouter la pipe aux déclarations du module

Utilisation

<h1>{{ title | capitalize }}</h1>

c. Autre exemple : Filtre import { Pipe, PipeTransform } from '@angular/core';

@Pipe({

name: 'filter'

})

export class FilterPipe implements PipeTransform {

transform(value: any, filterBy?: string): any {

filterBy = filterBy ? filterBy.toLocaleLowerCase() : null;

return filterBy ? value.filter((item: any) =>

item.toLocaleLowerCase().indexOf(filterBy) !== -1) : value;

}

}

Utilisation

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

@Component({

selector: 'app-product-list',

template: `

<div>

<h1>Products</h1>

<input type="text" [(ngModel)]="listFilter">

<ul>

<li *ngFor="let fruit of fruits | filter:listFilter">{{ fruit }}</li>

</ul>

Value reçue à transformer + éventuels

paramètres passés (pour faire comme

DatePipe par exemple)

L’item pourrait être fortement

typé (product) et filtrer sur le

nom de product par exemple

Page 21: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

21

</div>

`

})

export class ProductListComponent {

listFilter: string;

fruits = ['banane', 'pêche', 'poire'];

}

10. Debug (avec sourceMap)

Augury

Extension chrome

On peut debug le code TypeScript depuis

Chrome avec sourcemap activé (true) dans

le fichier de configuration de TypeScript

(tsConfig.json du dossier « src »)

Page 22: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

22

11. Routing & navigation Documentation

a. Au plus simple

On a des components simples avec le minimum de code.

Template de l’AppComponent

<div>

<nav>

<a [routerLink]="['/']">Home</a>

<a [routerLink]="['/products']">Product list</a>

</nav>

<router-outlet></router-outlet>

</div>

On définit directement le routing dans l’AppModule :

import de RouterModule

définition des routes import { BrowserModule } from '@angular/platform-browser';

import { NgModule } from '@angular/core';

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

import { AppComponent } from './app.component';

import { HomeComponent } from './home/home.component';

import { ProductListComponent } from './product/product-list.component';

@NgModule({

declarations: [

AppComponent,

HomeComponent,

ProductListComponent

],

imports: [

BrowserModule,

RouterModule.forRoot([

{ path: '', component: HomeComponent },

{ path: 'products', component: ProductListComponent }

])

],

providers: [],

bootstrap: [AppComponent]

})

export class AppModule { }

Page 23: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

23

b. Location stratégies Documentation

2 stratégies :

path (par défaut) utilisation html5 history permettant d’avoir des uri propres sans hash

mais pas supporté pour tous les navigateurs (« pushState »)

hash avec # dans l’url. C’est l’ancienne méthode qui permet de faire des spa. (à gauche

de l’url ce qui est géré côté serveur, à droite ce qui est géré côté client et peut être

intercepté avec l’event « hashchange »)

Pour changer la stratégie

RouterModule.forRoot(APP_ROUTES, { useHash: true });

c. Passage de paramètre On ajoute une route acceptant un paramètre id dans AppModule (et on crée un nouveau

component ProductDetailComponent + ajout aux déclarations du module)

On définit un lien avec passage d’id (template de ProductListComponent par exemple)

Ou

Page 24: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

24

Réception du paramètre de route

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

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

@Component({

selector: 'app-product-detail',

template: `

<p>{{ message }}</p>

`

})

export class ProductDetailComponent {

message: string;

constructor(private _route: ActivatedRoute) {

this.message = 'Product id:' + _route.snapshot.params['id'];

}

}

d. Navigation par programmation import { Component } from '@angular/core';

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

@Component({

selector: 'app-product-list',

template: `

<div>

<h1>Products</h1>

<button (click)="onNavigate()">Navigate</button>

</div>

`

})

export class ProductListComponent {

constructor(private _router: Router) { }

onNavigate() {

this._router.navigate(['/products', 1000]);

}

}

e. Autres paramètres de routes Lien avec query et fragment

Navigation par programmation

this._router.navigate(['/products', 1000], { queryParams: { q: 'xyz' },

fragment: 'section2' });

S’abonner aux observables

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

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

@Component({

selector: 'app-product-detail',

template: `

<p>{{ message }}</p>

<p>Id: {{ id }}</p>

<p>Recherche: {{ search }}</p>

<p>Section: {{ section }}</p>

`

})

Entourer le fragment de ‘’

Objet contenant queryParams

(object) et fragment (string)

Page 25: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

25

export class ProductDetailComponent {

message: string;

id: string;

search: string;

section: string;

constructor(private _route: ActivatedRoute) {

this.message = 'Product id:' + _route.snapshot.params['id'];

_route.params.subscribe((param) => this.id = param['id']);

_route.queryParams.subscribe((queryParam) => this.search =

queryParam['q']);

_route.fragment.subscribe((fragment) => this.section = fragment);

}

}

Exemple d’url générée

Bonne pratique : se désabonner des observables on ngOnDestroy

Exemple

import { Component, OnDestroy } from '@angular/core';

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

import { Subscription } from 'rxjs/Rx';

@Component({

selector: 'app-product-detail',

template: `

<p>Id: {{ id }}</p>

`

})

export class ProductDetailComponent implements OnDestroy {

id: string;

subscription: Subscription;

constructor(private _route: ActivatedRoute) {

this.subscription = _route.params.subscribe((param) => this.id =

param['id']);

}

ngOnDestroy() {

this.subscription.unsubscribe();

}

}

Page 26: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

26

f. Préserver les query params/ fragment quand on navigue vers une autre url Exemple on ajout un lien dans le template de ProductDetailComponent

<a [routerLink]="['/']" [preserveQueryParams]="true"

[preserveFragment]="true">Home</a>

Par programmation

this._router.navigate(['/'], { preserveQueryParams: true,

preserveFragment: true });

g. Redirection Exemple redirrige vers « /products » depuis la page d’accueil

Ou défaut

Exemple redirection vers la page d’accueil

h. Child routes Pour mieux organiser son routing

Automatiquement « products »

est ajouté en début de chemins

ce qui donne « /products » et

« /products/ :id »

Page 27: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

27

i. RouterLinkActive Exemple dans le template de AppComponent

CSS de AppComponent

routerLinkActiveOptions + exact permet de définir que la classe css est ajoutée si le

chemin correspond exactement. Sans cela par exemple pour la route « /products » ayant

des children, le lien serait toujours actif que l’on sur « /products » ou « products/ :id ».

Avec « exact » seul le chemin « /products » sera pris en compte pour l’ajout de la classe

CSS active.

j. Route guards Permet de contrôler l’activation et la désactivation d’une route. (Exemple avec une

simple boite de dialogue demandant la confirmation pour naviguer)

Création du guard

import { CanActivate, CanDeactivate, RouterStateSnapshot, ActivatedRouteSnapshot } from

'@angular/router';

import { Observable } from 'rxjs/Rx';

export interface ComponentCanDeactivate {

canDeactivate: () => boolean | Observable<boolean>;

}

export class ProductDetailGuard implements CanActivate,

CanDeactivate<ComponentCanDeactivate> {

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):

Observable<boolean> | boolean {

return confirm('Navigate?');

}

canDeactivate(component: ComponentCanDeactivate): Observable<boolean> | boolean {

return component.canDeactivate ? component.canDeactivate() : true;

}

}

Enregistrer le guard dans les providers du module

Code ajouté dans le component pour la désactivation

On pourrait par exemple demander à sauvegarder des données avant de quitter la page

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

import { Observable } from 'rxjs/Rx';

@Component({

selector: 'app-product-detail',

template: `

<p>Details</p>

`

})

export class ProductDetailComponent implements OnDestroy {

Page 28: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

28

canDeactivate(): Observable<boolean> | boolean {

return confirm('Leave?');

}

}

(Penser à se désabonner avec ngOnDestroy si utilisation d’un observable)

Utilisation du guard sur une route (importer le guard)

Autre exemple : Autorisation

On vérifie par exemple que l’utilisateur est authentifié par accéder à la page sinon on le

redirige vers la page de login (en passant l’url vers laquelle il sera redirigé une fois

authentifié)

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {

if (this.userProfileService.isLoggedIn) {

return true;

}

this.router.navigate(['/login'], { queryParams: { redirectTo: state.url } });

return false;

}

k. Mieux organiser ses routes

Child routes

Configuration du routing

Ajout du routing dans les imports d’AppModule

(+ Components dans les déclarations)

Importer le router

Page 29: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

29

Fichier dédié au routing « app.routing.ts »

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

import { HomeComponent } from './home/home.component';

import { PRODUCT_ROUTES } from './product/product.routes';

const APP_ROUTES: Routes = [

{ path: '', component: HomeComponent },

{ path: 'products', children: PRODUCT_ROUTES },

{ path: '**', redirectTo: '' }

];

export const routing = RouterModule.forRoot(APP_ROUTES);

Child routes « product.routes.ts »

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

import { ProductListComponent } from './product-list.component';

import { ProductDetailComponent } from './product-detail.component';

export const PRODUCT_ROUTES: Routes = [

{ path: '', component: ProductListComponent },

{ path: ':id', component: ProductDetailComponent }

];

« AppModule »

import { BrowserModule } from '@angular/platform-browser';

import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

import { HomeComponent } from './home/home.component';

import { ProductListComponent } from './product/product-list.component';

import { ProductDetailComponent } from './product/product-

detail.component';

import { routing } from './app.routing';

@NgModule({

declarations: [

AppComponent,

HomeComponent,

ProductListComponent,

ProductDetailComponent

],

imports: [

BrowserModule,

routing

],

providers: [],

bootstrap: [AppComponent]

})

export class AppModule { }

Page 30: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

30

l. Créer des modules pour le routing

ProductRoutingModule

import { NgModule } from '@angular/core';

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

import { ProductListComponent } from './product-list.component';

import { ProductDetailComponent } from './product-detail.component';

const routes: Routes = [

{

path: 'products',

children: [

{ path: '', component: ProductListComponent },

{ path: ':id', component: ProductDetailComponent }

]

}

];

@NgModule({

imports: [RouterModule.forChild(routes)],

exports: [RouterModule]

})

export class ProductRouterModule { }

export const routedComponents = [

ProductListComponent,

ProductDetailComponent

];

Feature module avec un

module de routing

(utilisant « forChild »)

AppModule avec un module de

routing AppRoutingModule +

ajout dans les imports du

feature module ProductModule

imports

imports

imports

Page 31: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

31

ProductModule

import { NgModule } from '@angular/core';

import { CommonModule } from '@angular/common';

import { ProductRouterModule, routedComponents } from './product-

routing.module';

@NgModule({

imports: [

CommonModule,

ProductRouterModule

],

declarations: [routedComponents]

})

export class ProductModule { }

AppRoutingModule

import { NgModule } from '@angular/core';

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

import { HomeComponent } from './home/home.component';

const routes: Routes = [

{ path: '', component: HomeComponent },

{ path: '**', redirectTo: '' }

];

@NgModule({

imports: [RouterModule.forRoot(routes)],

exports: [RouterModule]

})

export class AppRoutingModule { }

AppModule

import { BrowserModule } from '@angular/platform-browser';

import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

import { HomeComponent } from './home/home.component';

import { AppRoutingModule } from './app-routing.module';

import { ProductModule } from './product/product.module';

@NgModule({

declarations: [

AppComponent,

HomeComponent

],

imports: [

BrowserModule,

ProductModule,

AppRoutingModule

],

providers: [],

bootstrap: [AppComponent]

})

export class AppModule { }

Page 32: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

32

m. Lazy loading AppRoutingModule

import { NgModule } from '@angular/core';

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

import { HomeComponent } from './home/home.component';

const routes: Routes = [

{ path: '', component: HomeComponent },

{ path: 'products', loadChildren: 'app/product/product.module#ProductModule' },

{ path: '**', redirectTo: '' }

];

@NgModule({

imports: [RouterModule.forRoot(routes)],

exports: [RouterModule]

})

export class AppRoutingModule { }

Modification ProductRoutingModule

import { NgModule } from '@angular/core';

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

import { ProductListComponent } from './product-list.component';

import { ProductDetailComponent } from './product-detail.component';

const routes: Routes = [

{

path: '',

children: [

{ path: '', component: ProductListComponent },

{ path: ':id', component: ProductDetailComponent }

]

}

];

@NgModule({

imports: [RouterModule.forChild(routes)],

exports: [RouterModule]

})

export class ProductRouterModule { }

export const routedComponents = [

ProductListComponent,

ProductDetailComponent

];

AppModule

On supprime des imports « ProductModule »

On peut observer que le module ProductModule est chargé seulement à la demande/

quand on a besoin.

On définit une route avec un chemin vide

(« /products » étant désormais défini dans

AppRoutingModule) + les routes en children

Page 33: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

33

n. PreloadinStrategy Documentation

12. Services

a. Dependency injection

Création d’un service. Exemple, générer le service « ProductService » avec Angular-Cli :

ng g service product/Product

import { Injectable } from '@angular/core';

import { Product } from './product';

@Injectable()

export class ProductService {

getProducts(): Product[] {

return [{ id: 1, name: 'Product 1' }, { id: 2, name: 'Product 2' }];

}

}

Injector

Component

constructor(private _myService : MyService){}

Injection du service

dans le constructor du

component

Service

export class MyService {}

Page 34: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

34

On peut créer un model « Product »

export class Product {

id: number;

name: string;

}

Enregistrer le service dans le tableau de providers du module.

Utilisation du service (component, etc.)

import { Component, OnInit } from '@angular/core';

import { Product } from './product';

import { ProductService } from './product.service';

@Component({

selector: 'app-product-list',

template: `

<div>

<h1>Product list</h1>

<ul>

<li *ngFor="let product of products">{{ product.name }}</li>

</ul>

</div>

`

})

export class ProductListComponent implements OnInit {

products: Product[];

constructor(private _productService: ProductService) { }

ngOnInit() {

this.products = this._productService.getProducts();

}

}

b. http Documentation, headers

Ajouter au tableau d’ « imports » du module le module HttpModule

import { HttpModule } from '@angular/http';

Avec Observable Création d’un dossier api avec un fichier json de données d’exemple à la racine du

dossier « src »

{

"data":[

{

"id": 1,

"name": "Product 1"

},

{

"id": 2,

"name": "Product 2"

}

]

}

Page 35: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

35

Modification du service

import { Injectable } from '@angular/core';

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

import { Observable } from 'rxjs/Observable';

import 'rxjs/add/operator/catch';

import 'rxjs/add/operator/do';

import 'rxjs/add/operator/map';

import 'rxjs/add/observable/throw';

import { Product } from './product';

@Injectable()

export class ProductService {

constructor(private http: Http) { }

getProducts(): Observable<Product[]> {

return this.http.get('api/products.json')

.map((response: Response) => <Product[]>response.json().data)

.do(data => console.log(data))

.catch(error => this.handleError(error));

}

private handleError(error: Response) {

console.error(error);

return Observable.throw(`Error status code ${error.status} at

${error.url}`);

}

}

Component

import { Component, OnInit } from '@angular/core';

import { Product } from './product';

import { ProductService } from './product.service';

@Component({

selector: 'app-product-list',

template: `

<div>

<h1>Product list</h1>

<ul>

<li *ngFor="let product of products">{{ product.name }}</li>

</ul>

</div>

`

})

export class ProductListComponent implements OnInit {

products: Product[];

errorMessage: string;

constructor(private _productService: ProductService) { }

ngOnInit() {

this._productService.getProducts()

.subscribe(

products => this.products = products,

error => this.errorMessage = <any>error

);

Imports utilsés avec

l’observable retourné par la

méthode get de http

Page 36: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

36

}

}

CRUD import { Injectable } from '@angular/core';

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

import { Observable } from 'rxjs/Observable';

import 'rxjs/add/operator/catch';

import 'rxjs/add/operator/do';

import 'rxjs/add/operator/map';

import 'rxjs/add/operator/share';

import 'rxjs/add/operator/toPromise';

import 'rxjs/add/observable/throw';

import { Post } from './post';

@Injectable()

export class PostService {

_headers: Headers;

_baseUrl: string;

constructor(private _http: Http) {

this._baseUrl = 'http://localhost:3000/api/v1/posts';

this._headers = new Headers({ 'Content-Type': 'application/json' });

}

getPosts(): Observable<Post[]> {

return this._http.get(this._baseUrl)

.map((response: Response) => <Post[]>response.json())

.do((data) => console.log(data))

.catch((error) => this.handleError(error));

}

getPost(id: any): any {

return this._http.get(`${this._baseUrl}/${id}`)

.map((response: Response) => <Post>response.json())

.do((data) => console.log(data))

.catch((error) => this.handleError(error));

}

addPost(post: Post): Observable<any> {

return this._http

.post(this._baseUrl, JSON.stringify(post), { headers: this._headers })

.map((response) => response.json())

.do((data) => console.log(data))

.catch((error) => this.handleError(error));

}

updatePost(id: any, post: Post): Observable<any> {

return this._http

.put(`${this._baseUrl}/${id}`, JSON.stringify(post), { headers: this._headers })

.map((response) => response.json())

.do((data) => console.log(data))

.catch((error) => this.handleError(error));

}

deletePost(id: any): Observable<any> {

return this._http.delete(`${this._baseUrl}/${id}`)

.map((response) => response.json())

.do((data) => console.log(data))

.catch((error) => this.handleError(error));

}

private handleError(error: Response) {

console.error(error);

return Observable.throw(`Error status code ${error.status} at ${error.url}`);

Page 37: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

37

}

}

Async pipe import { Component, OnInit } from '@angular/core';

import { Product } from './product';

import { ProductService } from './product.service';

@Component({

selector: 'app-product-list',

template: `

<div>

<h1>Product list</h1>

<ul>

<li *ngFor="let product of asyncProducts | async">{{ product.name

}}</li>

</ul>

</div>

`

})

export class ProductListComponent implements OnInit {

asyncProducts: any;

constructor(private _productService: ProductService) { }

ngOnInit() {

// async pipe

this.asyncProducts = this._productService.getProducts();

}

}

Avec promise Service

import { Injectable } from '@angular/core';

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

import { Observable } from 'rxjs/Observable';

import 'rxjs/add/operator/catch';

import 'rxjs/add/operator/do';

import 'rxjs/add/operator/map';

import 'rxjs/add/operator/toPromise';

import { Product } from './product';

@Injectable()

export class ProductService {

constructor(private http: Http) { }

getProductsP(): Promise<Product[]> {

return this.http.get('api/products.json') // returns an observable

.toPromise()

.then(response => {

return <Product[]>response.json().data;

})

.catch((error: any) => {

return Promise.reject('Cannot load products');

});

}

}

Component

this._productService.getProductsP()

.then(

products => this.products = products,

Page 38: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

38

error => this.errorMessage = <any>error

);

13. Mean Créer un projet avec Angular-CLI

ng new <project-name>

Ajout des dépendances Node (Mongoose ou Mongojs)

npm i express mongojs body-parser ejs -S Créer le serveur

var express = require('express'),

path = require('path'),

bodyParser = require('body-parser'),

api = require('./routes/api');

var app = express();

// view engine

app.set('view engine', 'ejs');

app.engine('html', require('ejs').renderFile);

//

app.use(express.static(path.join(__dirname, 'dist')));

// body parser

app.use(bodyParser.json());

app.use(bodyParser.urlencoded({ extended: false }));

// cors

app.use(function (req, res, next) {

res.setHeader('Access-Control-Allow-Origin', '*');

res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS,

PUT, PATCH,DELETE');

res.setHeader('Access-Control-Allow-Headers', 'X-Requested-

With,content-type');

next();

});

// api

app.use('/api/v1/', api);

// render index page

app.get('*', function (req, res) {

res.sendFile(path.join(__dirname, 'dist/index.html'));

});

app.listen(3000, function () {

console.log('Server started on port 3000...');

});

Création des routes de l’Api (dans un dossier routes par exemple)

var express = require('express'),

router = express.Router(),

mongojs = require('mongojs');

var db = mongojs('mongodb://marie:[email protected]:61059/ blog',

['posts']);

// get http://localhost:3000/api/v1/posts

router.get('/posts', function (req, res, next) {

db.posts.find(function (err, posts) {

if (err) {

res.send(err);

Page 39: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

39

} else {

res.json(posts);

}

});

});

// get one

router.get('/posts/:id', function (req, res, next) {

db.posts.findOne({

_id: mongojs.ObjectId(req.params.id)

}, function (err, post) {

if (err) {

res.send(err);

} else {

res.json(post);

}

});

});

// add

router.post('/posts', function (req, res, next) {

var post = req.body;

if (post.title === '' || post.content === '') {

res.status(400);

res.json({

"error": "Invalid data"

});

} else {

db.posts.save(post, function (err, result) {

if (err) {

res.send(err);

} else {

res.json(result);

}

});

}

});

// update

router.put('/posts/:id', function (req, res, next) {

var post = req.body;

db.posts.update({

_id: mongojs.ObjectId(req.params.id)

}, post, {}, function (err, result) {

if (err) {

res.send(err);

} else {

res.json(result);

}

});

});

// delete

router.delete('/posts/:id', function (req, res, next) {

db.posts.remove({

_id: mongojs.ObjectId(req.params.id)

}, '', function (err, result) {

if (err) {

res.send(err);

} else {

res.json(result);

}

});

});

module.exports = router;

Page 40: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

40

14. Firebase Site. Il est possible d’avoir gratuit

Créer un projet / ou importer un projet Google existant

Dans l’onglet database il est possible de créer différentes collections

Il est possible également d’importer des données au format json.

Il est possible de changer les règles si on veut autoriser l’accès sans être connecté

Pour obtenir les identifiants, aller sur l’onglet « overview » et cliquer sur « Ajouter

firebase à votre application web »

Pour se connecter à sa base avec Angular.. Installer AngularFire2

npm i firebase angularfire2 -S

Dans AppModule ou un fichier à part

export const firebaseConfig = {

apiKey: 'AIzaSyAOZOCDwA35BCR6IEdnC-XfFQphk2zbikw',

Page 41: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

41

authDomain: 'fb-project-b2857.firebaseapp.com',

databaseURL: 'https://fb-project-b2857.firebaseio.com',

storageBucket: 'fb-project-b2857.appspot.com'

};

Dans AppModule

Importer la configuration et le module

import { firebaseConfig } from './firebase.config';

import { AngularFireModule } from 'angularfire2';

… et les ajouter aux imports du module

imports: [

BrowserModule,

ReactiveFormsModule,

routing,

AngularFireModule.initializeApp(firebaseConfig)

],

Utilisation dans un service

import { Injectable } from '@angular/core';

import { AngularFire, FirebaseListObservable } from 'angularfire2';

import 'rxjs/add/operator/map';

import { Category } from './category';

import { Post } from './post';

@Injectable()

export class PostService {

_posts: FirebaseListObservable<Post[]>;

_categories: FirebaseListObservable<Category[]>;

constructor(private _angularFire: AngularFire) { }

getPosts(category?: any): FirebaseListObservable<Post[]> {

if (category !== null) {

this._posts = this._angularFire.database.list('posts', {

query: {

orderByChild: 'category',

equalTo: category

}

});

return this._posts;

} else {

this._posts = this._angularFire.database.list('posts');

return this._posts;

}

}

getPost(key: any) {

return this._angularFire.database.object(`/posts/${key}`);

}

addPost(post: Post): firebase.Promise<any> {

return this._posts.push(post);

}

updatePost(key: any, post: Post): firebase.Promise<any> {

return this._posts.update(key, post);

}

deletePost(key: any): firebase.Promise<any> {

Page 42: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

42

return this._posts.remove(key);

}

getCategories() {

this._categories = this._angularFire.database.list('categories');

return this._categories;

}

}

Note : on utilse la clé générée ($key) par firebase que l’on ajoute à chaque model

Exemple le model Post

export class Post {

constructor(public $key: string,

public title: string,

public content: string,

public category: string) { }

}

Pour obtenir les résultats du service il suffit de souscrire aux observables (requêtes

GET) et aux promises pour les requêtes POST, PUT, DELETE.

Exemples

GET

ngOnInit() {

this._postService.getCategories().subscribe((categories) => {

this.categories = categories;

});

this._getPosts();

}

POST

onSubmit() {

if (this.form.valid) {

this._postService.addPost(this.form.value).then(() => {

this._router.navigate(['/posts']);

});

}

}

Page 43: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

43

15. Forms Documentation, form validation

a. Template driven « Comme avec Angular 1 ». Se concentre sur le template

Ajouter au tableau d’ « imports » du module le module FormsModule

import { FormsModule } from '@angular/forms';

Directives : ngForm, ngModel, ngModelGroup

State et classes CSS (sur form et chaque html element):

- pristine/ng-pristine (non modifié), dirty/ng-dirty (modifié)

- valid/ng-valid, ng-invalid, errors (object)

- touched/ng-touched (visité), untouched/ng-untouched

<h1>Sign up</h1>

<form class="form-horizontal" (ngSubmit)="onSubmit(signupForm)" #signupForm="ngForm">

<fieldset>

<div class="form-group"

[ngClass]="{'has-error': (firstNameVar.touched || firstNameVar.dirty) &&

!firstNameVar.valid }">

<label class="col-md-2 control-label" for="firstNameId">First Name</label>

<div class="col-md-8">

<input class="form-control"

type="text"

id="firstNameId"

placeholder="First Name (required)"

required

minlength="3"

[(ngModel)]= "user.firstName"

name="firstName"

#firstNameVar="ngModel" />

<span class="help-block"

*ngIf="(firstNameVar.touched || firstNameVar.dirty) && firstNameVar.errors">

<span *ngIf="firstNameVar.errors.required">Please enter your first

name.</span>

<span *ngIf="firstNameVar.errors.minlength">The first name must be longer

than 3 characters.</span>

</span>

</div>

</div>

</fieldset>

<button type="submit"[disabled]="!signupForm.valid" class="btn btn-

primary">Submit</button>

</form>

Binding à l’objet user du component

Messages d’erreurs affichés selon l’erreur

Référence utilisée pour les messages d’erreurs

Classe css « has-error » ajoutée si le champ a été

visité ou modifié et qu’il a des erreurs

On passe la référence du

formulaire à la soumission

Bouton d’envoi grisé si le formulaire a des erreurs

Règles de validation permettant de

déterminer si le champ est valide (required,

minlength,maxlength,pattern)

Page 44: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

44

Component

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

import { NgForm } from '@angular/forms';

@Component({

selector: 'app-signup',

templateUrl: './signup.component.html'

})

export class SignupComponent {

user = {

firstName: 'Marie',

email: '[email protected]'

};

onSubmit(signupForm : NgForm) {

console.log(signupForm.form, signupForm.value);

}

}

b. Reactive forms Documentation

Se concentre d’avantage sur le component

Ajouter au tableau d’ « imports » du module le module ReactiveFormsModule

import { ReactiveFormsModule } from '@angular/forms';

Directives :

formGroup

formControl

formControlName

formGroupName

formArrayName <h1>Sign up</h1>

<form class="form-horizontal" novalidate autocomplete="off" (ngSubmit)="onSubmit()"

[formGroup]="signupForm">

<fieldset>

<div class="form-group"

[ngClass]="{'has-error': (signupForm.get('firstName').touched ||

signupForm.get('firstName').dirty) && !signupForm.get('firstName').valid }">

<label class="col-md-2 control-label" for="firstNameId">First Name</label>

<div class="col-md-8">

<input class="form-control" id="firstNameId" type="text" placeholder="First

Name (required)" formControlName="firstName"/>

<span class="help-block" *ngIf="(signupForm.get('firstName').touched ||

signupForm.get('firstName').dirty) && signupForm.get('firstName').errors">

<span *ngIf="signupForm.get('firstName').errors.required">Please enter your

first name.</span>

<span *ngIf="signupForm.get('firstName').errors.minlength">The first name

must be longer than 3 characters.</span>

</span>

</div>

</div>

</fieldset>

<button type="submit" class="btn btn-primary"

[disabled]="!signupForm.valid">Submit</button>

</form>

Objet avec couples name/value (ou

groupes si utilisation de

ngModelGroup)

Permet de définir avec ngModel

des valeurs par défaut

Page 45: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

45

Component

import { Component, OnInit } from '@angular/core';

import { FormGroup, FormBuilder, Validators } from '@angular/forms';

@Component({

selector: 'app-signup',

templateUrl: './signup.component.html'

})

export class SignupComponent implements OnInit {

signupForm: FormGroup;

constructor(private fb: FormBuilder) { }

ngOnInit(): void {

this.signupForm = this.fb.group({

'firstName': ['Marie', [Validators.required,

Validators.minLength(3)]]

}

onSubmit() {

console.log(this.signupForm, this.signupForm.value);

}

}

Sans FormBuilder

import { Component, OnInit } from '@angular/core';

import { FormGroup, FormControl, Validators } from '@angular/forms';

@Component({

selector: 'app-signup',

templateUrl: './signup.component.html',

styleUrls: ['./signup.component.css']

})

export class SignupComponent implements OnInit {

signupForm: FormGroup;

ngOnInit(): void {

// sans FormBuilder

this.signupForm = new FormGroup({

'firstName': new FormControl('Marie', [Validators.required,

Validators.minLength(3)])

});

}

onSubmit() {

console.log(this.signupForm, this.signupForm.value);

}

}

Built-in validators (documentation)

required

requiredTrue

minLength

maxLength

pattern

nullValidator

compose

composeAsync

Utilsation du form builder

qui permet de définir

facilement les FormGroup,

FormControls et validators

formControlName(Chaine de

caractères pour éviter les pb après

minification)

Utilisation de FormGroup (pour la

form ou groupes de controls) et

FormControl

Validators=functions qui sont appelées pour la validation,

ici on ne fait que les référencer (on ne les appelle pas)

Default value du formControl

(on peut laisser chaine vide)

Un seul validator ou un tableau

de validators

Page 46: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

46

Ecouter les changements de statut du formulaire (VALID ou INVALID)

ngOnInit(): void {

this.signupForm = new FormGroup({

'firstName': new FormControl('Marie', [Validators.required,

Validators.minLength(3)])

});

this.signupForm.statusChanges.subscribe(

(data: any) => console.log(data)

);

}

16. Animations Documentation

17. Test Documentation, Jasmine, expectations, testing-angular-2-http-services-with-jasmine

a. Test de service import { Injectable } from '@angular/core';

@Injectable()

export class ProductService {

getData(): string {

return 'My data';

}

getDataAsync(): Promise<string> {

return new Promise<string>((resolve) => {

setTimeout(() => {

resolve('My async data');

}, 1000);

});

}

}

Test au plus simple

/* tslint:disable:no-unused-variable */

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

import { ProductService } from './product.service';

describe('ProductService', () => {

let service: ProductService;

beforeEach(() => {

service = new ProductService();

});

it('should get data', () => {

let result = service.getData();

expect(result).toEqual('My data');

});

it('should get async data', ((done) => {

service.getDataAsync().then((result) => {

expect(result).toEqual('My async data');

done();

});

}));

});

Page 47: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

47

b. Test de service http

import { PostService } from './post.service';

import { Observable } from 'rxjs/Rx';

import { TestBed, async, inject, getTestBed } from '@angular/core/testing';

import {

Http,

Response,

ResponseOptions,

BaseRequestOptions

} from '@angular/http';

import { MockBackend } from '@angular/http/testing';

describe('PostService', () => {

beforeEach(() => {

TestBed.configureTestingModule({

providers: [

PostService,

MockBackend,

BaseRequestOptions,

{

provide: Http,

useFactory: (mockBackend, defaultOptions) => {

return new Http(mockBackend, defaultOptions);

},

deps: [MockBackend, BaseRequestOptions]

}

]

});

});

describe('Async tests', () => {

let postService: PostService;

let mockBackend;

beforeEach(inject([PostService, MockBackend], (_postService, _mockBa

ckend) => {

postService = _postService;

mockBackend = _mockBackend;

}));

it('should return an Observable', (done) => {

const mockResponse = {

data: [

{ id: 1, title: 'Post 1', content: 'Content 1' },

{ id: 2, title: 'Post 2', content: 'Content 2' },

{ id: 3, title: 'Post 3', content: 'Content 3' }

Page 48: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

48

]

};

mockBackend.connections.subscribe((connection) => {

connection.mockRespond(new Response(new ResponseOptions({ bo

dy: mockResponse.data })));

});

postService.getPosts().subscribe((posts) => {

expect(posts.length).toBe(3);

expect(posts[0].title).toEqual('Post 1');

expect(posts[1].title).toEqual('Post 2');

expect(posts[2].title).toEqual('Post 3');

done();

});

});

});

});

c. Tester un component avec injection Le component utilisé

import { Component, OnInit } from '@angular/core';

import { ProductService } from './product.service';

@Component({

selector: 'app-product-list',

template: `

<p id="data">{{data}}</p>

<p id="async-data">{{asyncData}}</p>

`,

styles: []

})

export class ProductListComponent implements OnInit {

data: string;

asyncData: string;

constructor(private _productService: ProductService) { }

ngOnInit() {

this.data = this._productService.getData();

// async data

this._productService.getDataAsync().then((result) => {

this.asyncData = result;

});

}

}

Page 49: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

49

Préparation

/* tslint:disable:no-unused-variable */

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

import { By } from '@angular/platform-browser';

import { DebugElement } from '@angular/core';

import { ProductListComponent } from './product-list.component';

import { ProductService } from './product.service';

describe('ProductListComponent', () => {

let component: ProductListComponent;

let fixture: ComponentFixture<ProductListComponent>;

let service: ProductService;

beforeEach(async(() => {

TestBed.configureTestingModule({

declarations: [ProductListComponent],

providers: [ProductService]

})

.compileComponents();

}));

beforeEach(() => {

fixture = TestBed.createComponent(ProductListComponent);

component = fixture.componentInstance;

service = fixture.debugElement.injector.get(ProductService);

fixture.detectChanges();

});

/* tests */

});

Tester que le component récupère bien les données au chargement

it('should get data', () => {

expect(component.data).toBe('My data');

});

Tester que le component récupère bien les données async

it('should get async data', async(() => {

let spy = spyOn(service, 'getDataAsync')

.and.returnValue(Promise.resolve('My async data'));

fixture.whenStable().then(() => {

expect(component.asyncData).toBe('My async data');

});

}));

Tester que le component affiche bien les données

it('should display data', () => {

let compiled = fixture.debugElement.nativeElement;

expect(compiled.querySelector('#data').textContent).toBe('My data');

});

Tester que le component affiche bien les données async

it('should display async data', async(() => {

let compiled = fixture.debugElement.nativeElement;

fixture.whenStable().then(() => {

expect(compiled.querySelector('#async-data').textContent).toBe('My

async data');

});

}));

Page 50: 1 Angular 2romagny13.com/wp-content/uploads/2015/04/Angular2.pdf3 19. Déploiement .....50 20. Migration .....50 4 1. EDI Visual Studio Code. Extensions : tsLint, snippets (peut être

50

18. AOT (AHEAD-OF-TIME COMPILATION) Documentation

19. Déploiement Documentation

20. Migration

Upgrade d’un projet Angular 2 fait avec une ancienne version d’Angular Cli vers Angular Cli 1.0.0 (On conserve le projet avec Angular 2)

a. Dans « package.json » remplacer en devDependencies:

"angular-cli": "1.0.0-beta.28.3",

… par

"@angular/cli": "1.0.0",

b. Renommer le fichier « angular-cli.json » en « .angular-cli.json »

c. Dans « .angular-cli.json » remplacer :

"environments": {

"source": "environments/environment.ts",

"dev": "environments/environment.ts",

"prod": "environments/environment.prod.ts"

}

… par

"environmentSource": "environments/environment.ts",

"environments": {

"dev": "environments/environment.ts",

"prod": "environments/environment.prod.ts"

}

Aide