Julien Lepasquier & Jean-Marc Debicki

Excilys - 2021

NGULAR

v12.x.x

Prérequis

npm install @angular/cli

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
  • ...
  • Mai 2021 : Angular 12

Application traditionnelle

  • Échanges client-serveur lourds
     
  • Rechargement de la page
     
  • Pas d'offline

Initial Request

Form Post

Client

Server

Page reload !

Single Page Application

  • Fluidité
     
  • User experience (UX)
     
  • Offline

Initial Request

XHR

{ ... } JSON

Client

Server

Typescript

Sur-ensemble de Javascript

Open source

Développé par Microsoft

Transpilé en Javascript

Typage statique

ECMAScript 6

Class, Interfaces

Syntaxe de Typescript

export class MonComponent {

    private maVariable: number | boolean | string = 'abc';
    protected array: any[];
    public abc: null | undefined;

    static readonly CONST = "CONSTANTE";

    constructor(private readonly service: Service) {}

    maFonction(attr: number): void {
      const constante = 123;
      let variable = "abc";
      let monArrowFunction = (a, b) => a+b;
    }
}

Survol d'Angular

Component tree

Root Component

 

 

 

Root Template

< >

Root Class

{ }

Child A Component

 

 

Child A Template

< >

Child A Class

{ }

Child B Component

 

 

Child B Template

< >

Child B Class

{ }

Grandchild Component

 

 

Grandchild Template

< >

Grandchild Class

{ }

Component

Life Cycle Hooks

@Component({
    selector: 'parent-component',
    template: '<child-component></child-component>',
    styleUrls: string[],
    ...
})
class ParentComponent {}
  
@Component({
    selector: 'child-component',
    template: 'Salut les grands malades !'
})
class ChildComponent {}

Injectable

@Injectable({
  providedIn: 'root'
})
class MonService {}

class MonComponent {
  constructor(private readonly service: Service) {}
}

Module

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

Directive

@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective {
    constructor(el: ElementRef) {
       el.nativeElement.style.backgroundColor = 'yellow';
    }
}
<p appHighlight>Je suis surligné</p>
<p>Pas moi</p>

*ngIf

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

[hidden]

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

*ngFor

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

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, ...

https://www.w3schools.com/jsref/dom_obj_event.asp

Data binding

{{ value }}

[property]="value"

(event)="handlerFunction($event)"

[(ngModel)]="property"

DOM

Component

Vue d'ensemble

Template

< >

Component

{     }

Injector

 

 

 

 

 

Service

{     }

LoginModule
​{}

{{ person.name }}

(click)="handle()"

Metadata

Directive

{ }

Metadata

UserModule
​{}

CardModule
​{}

ListModule
​{}

A vos claviers !

Excilys Cocktails

Génération "boilerplate" :

ng new first-app
  > CSS ?
    > SCSS

  > Routing ?
    > no

Excilys Cocktails

Lancement du serveur :

ng serve

Ou :

npm start

Excilys Cocktails

Arborescence

package.json

Excilys Cocktails

Un peu d'aide côté design : Angular Material

Installation :

ng add @angular/material

Excilys Cocktails

Ajout d'un header

Dans src/app, créer le composant Header :

ng generate component header

Excilys Cocktails

Dans src/app :

ng generate module custom-material

Excilys Cocktails

Affichage d'une recette

Composant Recipe :

ng generate component recipe

Excilys Cocktails

Création du modèle

recipe.model.ts

recipe-ingredient.model.ts

ingredient.model.ts

Excilys Cocktails

Création du modèle

import { RecipeIngredient } from './recipe-ingredient.model';

export class Recipe {
  id?: number;
  name: string;
  picture: string;
  description: string;
  ingredients: RecipeIngredient[];
  instructions: string[];
}

Excilys Cocktails

Création du modèle

import { Ingredient } from './ingredient.model';

export class RecipeIngredient {
  id?: number;
  ingredient: Ingredient;
  quantity: number;
  unit: string;
}

Excilys Cocktails

Création du modèle

export class Ingredient {
    name: string;
    id?: number;
}

Excilys Cocktails

Affichage des recettes

Paramètre d'entrée du composant :

@Input()
recipe: Recipe;

Excilys Cocktails

Affichage d'une liste de recettes

Composant Recipe List :

ng generate component recipe-list

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

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 :

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: number): 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

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

Pour les rapides

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

Formation Angular

By Julien Lepasquier

Formation Angular

  • 354