Anthony Salembier @ Excilys - 2019
NGULAR
v7.2.12

Prérequis
- NodeJS (LTS) v10.15.3
- NPM v6.4.1
- Angular CLI v7.3.8
- (opt) Git
- (opt) IDE Front : Visual Studio Code, Atom, Sublim Text, Webstorm (1 mois gratuit)

Présentation

Un peu d'histoire ...
- Juin 2012 - AngularJS (Miško Hevery et Adam Abronsw puis Google)
- Septembre 2016 - Angular 2
- Mars 2017 - Angular 4
- Novembre 2017 - Angular 5
- Avril 2018 - Angular 6
- Septembre/Octobre 2018 - Angular 7

Single Page Application
User Experience (UX)
Fluidité
Offline
Client <= Pages => Serveur
Client <= Ressources => Serveur

Typescript
Sur-ensemble de Javascript
Open source
Développé par Microsoft
Transpilé en Javascript
Typage statique
ECMAScript 6
Class, Interfaces

Survol d'Angular

Component tree


Component

Life Cycle Hooks
@Component({
selector: string,
templateUrl: string,
styleUrls: string[],
...
})

Injectable
@Injectable({
providedIn: ...
})

Directive
@Directive({
selector: string,
...
})

Module
@NgModule({
declarations: any[],
imports: any[],
exports: any[],
providers: any[],
...
})

Overview


Data binding


Template binding {{ }}
<div>
Hello {{ name }}
</div>

Dom events
<button (click)="doSomething()">
Click me !
</button>
Liste des HTML DOM Events sans le "on" :
click, dblclick, mousedown, keypress, change, resize, blur, focus, ...

*ngIf
<div *ngIf="expressionBooleenne">
Hello
</div>

[hidden]
<div [hidden]="expressionBooleenne">
Hello
</div>

*ngFor
<ul>
<li *ngFor="let item of itemList">
{{ item }}
</li>
</ul>

Au travail !

On veut du clean code !!
(Indentation, code aéré, performant, lisible, …)
Excilys Cocktails
Génération "boilerplate" :
ng new first-app --style=scss

Excilys Cocktails
Lancement du serveur :
ng serve
Ou :
npm start

Excilys Cocktails
Un peu d'aide côté design : Angular Material
Installation :
npm install @angular/material @angular/cdk --save

Excilys Cocktails
Dans src/app :
ng generate module custom-material

Excilys Cocktails
Arborescence
package.json

Excilys Cocktails
Ajout d'un header
Dans src/app, créer le composant Header :
ng generate component header

Excilys Cocktails
Création du modèle
Composant Recipe :
ng generate component recipe

Excilys Cocktails
Création du modèle
recipe.model.ts
ingredient.model.ts

Excilys Cocktails
Création du modèle
import { Ingredient } from './ingredient.model';
export class Recipe {
name: string;
picture: string;
description: string;
ingredients: Ingredient[];
instructions: string[];
}

Excilys Cocktails
Affichage des recettes
Paramètre d'entrée du composant :
@Input()
recipe: Recipe;

Excilys Cocktails
Affichage des recettes
Afficher la liste :
<app-recipe *ngFor="let recipe of recipes"
[recipe]="recipe">
</app-recipe>

Excilys Cocktails
Affichage des recettes
Afficher / masquer les détails :
<button (click)="toggleExpand()">
See more
</button>

Excilys Cocktails
Service RecipeService
Création du service :
ng generate service recipe --module=app

Excilys Cocktails
Service RecipeService
Refacto permettant de gérer l'asynchrone :
getRecipes(): Observable<Recipe[]> {
return of(RECIPES);
}

Excilys Cocktails
Récupération des données de l'Observable
Dans un composant appelant le getRecipes() du service.
this.recipeService.getRecipes().subscribe(
(result: Recipe[]) => {
// Traiter le résultat
},
(error) => {
// Traiter l'erreur
}
);

Excilys Cocktails
Passage au HttpClient :
Prérequis (In Memory Web API) :
npm install angular-in-memory-web-api --save

Excilys Cocktails
Passage au HttpClient (In Memory Web API) :
Dans src/app : in-memory-data.service.ts
import { InMemoryDbService } from 'angular-in-memory-web-api';
export class InMemoryDataService implements InMemoryDbService {
createDb() {
const recipes = [ (Ajouter le modèle mocké ici) ]
return {recipes};
}
}

Excilys Cocktails
Passage au HttpClient (In Memory Web API) :
imports: [
HttpClientInMemoryWebApiModule.forRoot(
InMemoryDataService, { dataEncapsulation: false }
)
],
AppModule :

Excilys Cocktails
Passage au HttpClient :
imports: [
...,
HttpClientModule,
...
]
AppModule :

Excilys Cocktails
Passage au HttpClient :
private recipeUrl = 'api/recipes';
getRecipes(): Observable<Recipe[]> {
return this.http.get<Recipe[]>(this.recipeUrl);
}
RecipeService :

Excilys Cocktails
Passage au HttpClient :
getRecipe(id: string): Observable<Recipe> {
return this.http.get<Recipe>(`${ this.recipeUrl }/${ id }`);
}
RecipeService, ajout d'une requêt "by ID" :

Excilys Cocktails
Routing :
ng generate module app-routing --flat --module=app
AppRoutingModule

Excilys Cocktails
Routing :
const routes: Routes = [
{
path: 'recipes',
component: RecipesComponent,
pathMatch: 'full'
},
{
path: '**',
redirectTo: 'recipes',
pathMatch: 'full'
}
];
AppRoutingModule

Excilys Cocktails
Routing :
@NgModule({
exports: [
RouterModule
],
imports: [
RouterModule.forRoot(routes)
]
})
AppRoutingModule

Excilys Cocktails
Routing :
<router-outlet></router-outlet>
Point d'entrée des routes

Excilys Cocktails
Routing :
Refacto : Modularisation de Recipe

A vous de jouer

Excilys Cocktails
Nouvelle page : Détail d'une recette
- Ajout d'une nouvelle page + composant : recipe-detail.component
- Navigation par le router : /recipes/:id
- Récupération d'une recette "byId"
TIPS :
- Créer une nouvelle route recipes/:id permet de variabiliser le param id
- L'attribut routerLink="/recipes/{{ recipe.id }}" permet de naviguer vers une la nouvelle route
- this.route.snapshot.paramMap.get('id') permet de récupérer le paramètre de la route à la création du composant (this.activatedRoute doit être injecté depuis le service Angular ActivatedRoute)

Excilys Cocktails
Nouvelle page : Formulaire d'ajout de recette
- Ajout d'une nouvelle page de formulaire de création de recette
- Ajout d'une nouvelle fonctionnalité POST dans le service
TIPS :
- Binding d'une donnée sur un élément HTML : [(ngModel)]="maVariable"

Excilys Cocktails
Suppression de recette
- Bouton de suppression de recette
- Ajout d'une nouvelle fonctionnalité DELETE dans le service

Overtime

Excilys Cocktails
Reactive Forms : Validation dynamique de formulaires
https://angular.io/guide/reactive-forms#add-a-formgroup

Excilys Cocktails
Pipes : Transformer les données
@Pipe({
name: 'orderBy'
})
export class OrderByPipe implements PipeTransform {
transform(param : InputType): OutputType {
doSomething();
return newValue;
}
}

Excilys Cocktails
Tests unitaires !
Karma + Jasmine

Excilys Cocktails
Animations : Animer les composants
https://angular.io/guide/animations#setup

Les liens utiles

Angular
By Anthony Salembier
Angular
- 487