Anthony Salembier @ Excilys - 2019
NGULAR
v7.2.12
- 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
User Experience (UX)
Fluidité
Offline
Client <= Pages => Serveur
Client <= Ressources => Serveur
Sur-ensemble de Javascript
Open source
Développé par Microsoft
Transpilé en Javascript
Typage statique
ECMAScript 6
Class, Interfaces
Life Cycle Hooks
@Component({
selector: string,
templateUrl: string,
styleUrls: string[],
...
})
@Injectable({
providedIn: ...
})
@Directive({
selector: string,
...
})
@NgModule({
declarations: any[],
imports: any[],
exports: any[],
providers: any[],
...
})
<div>
Hello {{ name }}
</div>
<button (click)="doSomething()">
Click me !
</button>
Liste des HTML DOM Events sans le "on" :
click, dblclick, mousedown, keypress, change, resize, blur, focus, ...
<div *ngIf="expressionBooleenne">
Hello
</div>
<div [hidden]="expressionBooleenne">
Hello
</div>
<ul>
<li *ngFor="let item of itemList">
{{ item }}
</li>
</ul>
On veut du clean code !!
(Indentation, code aéré, performant, lisible, …)
Génération "boilerplate" :
ng new first-app --style=scss
Lancement du serveur :
ng serve
Ou :
npm start
Un peu d'aide côté design : Angular Material
Installation :
npm install @angular/material @angular/cdk --save
Dans src/app :
ng generate module custom-material
Arborescence
package.json
Ajout d'un header
Dans src/app, créer le composant Header :
ng generate component header
Création du modèle
Composant Recipe :
ng generate component recipe
Création du modèle
recipe.model.ts
ingredient.model.ts
Création du modèle
import { Ingredient } from './ingredient.model';
export class Recipe {
name: string;
picture: string;
description: string;
ingredients: Ingredient[];
instructions: string[];
}
Affichage des recettes
Paramètre d'entrée du composant :
@Input()
recipe: Recipe;
Affichage des recettes
Afficher la liste :
<app-recipe *ngFor="let recipe of recipes"
[recipe]="recipe">
</app-recipe>
Affichage des recettes
Afficher / masquer les détails :
<button (click)="toggleExpand()">
See more
</button>
Service RecipeService
Création du service :
ng generate service recipe --module=app
Service RecipeService
Refacto permettant de gérer l'asynchrone :
getRecipes(): Observable<Recipe[]> {
return of(RECIPES);
}
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
}
);
Passage au HttpClient :
Prérequis (In Memory Web API) :
npm install angular-in-memory-web-api --save
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};
}
}
Passage au HttpClient (In Memory Web API) :
imports: [
HttpClientInMemoryWebApiModule.forRoot(
InMemoryDataService, { dataEncapsulation: false }
)
],
AppModule :
Passage au HttpClient :
imports: [
...,
HttpClientModule,
...
]
AppModule :
Passage au HttpClient :
private recipeUrl = 'api/recipes';
getRecipes(): Observable<Recipe[]> {
return this.http.get<Recipe[]>(this.recipeUrl);
}
RecipeService :
Passage au HttpClient :
getRecipe(id: string): Observable<Recipe> {
return this.http.get<Recipe>(`${ this.recipeUrl }/${ id }`);
}
RecipeService, ajout d'une requêt "by ID" :
Routing :
ng generate module app-routing --flat --module=app
AppRoutingModule
Routing :
const routes: Routes = [
{
path: 'recipes',
component: RecipesComponent,
pathMatch: 'full'
},
{
path: '**',
redirectTo: 'recipes',
pathMatch: 'full'
}
];
AppRoutingModule
Routing :
@NgModule({
exports: [
RouterModule
],
imports: [
RouterModule.forRoot(routes)
]
})
AppRoutingModule
Routing :
<router-outlet></router-outlet>
Point d'entrée des routes
Routing :
Refacto : Modularisation de Recipe
Nouvelle page : Détail d'une recette
TIPS :
Nouvelle page : Formulaire d'ajout de recette
TIPS :
Suppression de recette
Reactive Forms : Validation dynamique de formulaires
https://angular.io/guide/reactive-forms#add-a-formgroup
Pipes : Transformer les données
@Pipe({
name: 'orderBy'
})
export class OrderByPipe implements PipeTransform {
transform(param : InputType): OutputType {
doSomething();
return newValue;
}
}
Tests unitaires !
Karma + Jasmine
Animations : Animer les composants
https://angular.io/guide/animations#setup