Document Details

ArdentNoseFlute1516

Uploaded by ArdentNoseFlute1516

Instituts Supérieurs de Formation des Maîtres

Aymen Sellaouti

Tags

Angular JavaScript programming web development

Summary

This document provides an introduction to Angular, a JavaScript framework for building Single Page Applications (SPAs). It explores Node.js, a JavaScript runtime environment, and its key concepts. The document also touches on Angular's component-based architecture, templates, and metadata.

Full Transcript

Angular Introduction AYMEN SELLAOUTI 1 Références 2 C’est quoi NodeJs? 3 C’est quoi NodeJs? Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweigh...

Angular Introduction AYMEN SELLAOUTI 1 Références 2 C’est quoi NodeJs? 3 C’est quoi NodeJs? Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world. Environnement d’exécution JS Utilise V8 le moteur JS de Google. 4 Moteur Javascript : Javascript Engine  Tout code JavaScript que vous écrivez a besoin d’un moteur Javascript pour l’exécuter.  Le moteur JavaScript possède deux composants principaux: Memory Heap : sert à allouer la mémoire utilisée dans le programme. Call Stack (pile d’exécution) : contient les données des fonctions exécutées par le programme. 5 Moteur Javascript : Javascript Engine 6 V8 Javascript Engine  V8 est un moteur JavaScript développé par Google et utilisé par chrome pour exécuter du code JavaScript.  Il est Open Source  Ecrit en C++ https://v8.dev/ 7 Qu’est ce qu’un environnement d’exécution JS  Un environnement d’exécution JS est l’endroit ou votre code JS va être exécuté. C’est la ou vivra votre JavaScript Engine.  Il va, entre autre,. déterminer quels variables globales sont accessibles pour vous (window pour le runtime envirement de votre browser)  Ajax, DOM et d’autres API’s ne font pas parti de JavaScript. C’est l’environnement d’exécution Js (Ici fourni par votre Browser) qui les rend disponible. https://v8.dev/ 8 Est-ce que JavaScript est Synchrone ou Asynchrone ?  Js est SYNCHRONE.  Les fonctions asynchrones telles que setTimout ne font pas partie de JS.  Elle font partie des API de votre runtime envirement.  Donc JS peut agir d’une façon ASYNCHRONE mais ceci n’est pas innée, ce n’est pas dans son Core mais plutôt du au API offert par le runtime. Dans NodeJs c’est libuv qui permet cet aspet Asynchrone. https://nodejs.org/en/about/ 9 Asynchrone  Un code asynchrone est un code non bloquant  Une fonction non bloquante est une fonction qui s’exécute en parallèle avec le reste du code. Exemple : setTimeout, makeRequest, readFile. https://nodejs.org/en/about/ 10 Qu’est ce qu’un environnement d’exécution JS  Si on gardait uniquement l’aspect Synchrone de JS, ca sera un problème énorme avec le browser. La solution proposée par les API est l’ajout e la composante synchrone via l’event loop et le callback queue.  Ceci va permettre d’effectuer des traitements sans bloquer le stack du moteur JS. https://v8.dev/ 11 Comment ca marche dans le browser ??? A part le moteur JS, votre environnement possède des API’s qui permettent à votre Moteur JS d’exécuter certaines fonctionnalités comme le timeout, ou fetch. A ces API’s est associé un event loop et des callback queue.  Pour le browser vous avez l’API DOM. http://latentflip.com/loupe/ 12 Comment est né Node ?  Au départ on ne pouvait exécuter Js que dans un Browser. C’est lui qui fournissait son environnement d’exécution.  Une question a été donc posée. Pouvons nous exécuter du Js en dehors du browser ? Pouvons nous avoir du Js côté Serveur ? 13 Comment est né Node ? 2008 2009 14 Comment est né Node ? https://v8.dev/ 15 NodeJs un environnement d’exécution  Afin de s’exécuter, Javascript a besoin d’un environnement d’exécution.  C’est comme un conteneur qui contient tout ce qu’il vous faut pour exécuter du code Js.  Le noyau de l’environnement d’exécution est le moteur Js.  Il y a aussi les APIs Node  Libuv la bibliothèque qui permet de gérer les I/O Asynchrone  Les nodes Js Binding 16 NodeJs un environnement d’exécution Moteur JavaScript NodeJs APIs Bindings NodeJs Fs http path crypto 17 Asynchrone  Un code asynchrone est un code non bloquant.  Dans sa présentation, NodeJs se présente comme étant un environnement d’exécution JavaScript asynchrone et dirigé par les événements. Imaginez qu’on veuille lire deux fichiers indépendants. « Time Line » du Modèle « bloquant » « Time Line » du Modèle « Non-bloquant » 18 18 1 https://nodejs.org/en/about/ 8 Est-ce que NodeJs est Multi thread ?  NodeJs est monothread au départ puis le multithrading a été introduit.  Vous avez encore V8 comme Moteur Js.  La gestion de l’aspect Asynchrone est offerte par la bibliothèque libuv https://blog.logrocket.com/node-js-multithreading-worker-threads-why-they-matter/ 19 libuv  libuv est une bibliothèque multiplatforme écrite en C  Son rôle est de gérer les opération asynchrone d’I/O  Elle permet à plusieurs langages de s’y connecter via les connecteurs de bindings. Elle offre la partie principale qui gérer les traitements Asynchrone de NodeJs, l’EVENT LOOP. https://libuv.org/ 20 libuv Thread Pool Asynchrone I/O Gestion de fichiers Réseau Event Loop https://libuv.org/ 21 libuv Processus Thread Thread 1 Thread 2 Thread 3 Thread 4 Node Principal Pile Pile Pile Pile Pile Code d’exécution d’exécution d’exécution d’exécution d’exécution https://libuv.org/ 22 libuv  libuv offre un thread pool.  Le nombre de thread est par défaut de 4 et il est extensible jusqu’à 128  Afin de le modifier, il faut utiliser la variable d’environnement UV_THRADPOOL_SIZE  Le thread pool ne gère pas automatiquement toutes les opérations asynchrones.  L’idée de base est d’éviter ca et de déléguer ca à l’OS tant qu’il peut le faire. https://libuv.org/ 23 libuv  Le pool gère donc les opérations d'E/S asynchrones pour lesquelles le noyau de votre OS a une prise en charge faible  Ceci s’applique pour les opérations de système de fichiers (fs) et les opérations DNS (dns)  Il est également utilisé pour le travail asynchrone lié au processeur dans les modules principaux de Node.js, à savoir la compression (zlib) et la cryptographie (crypto). https://libuv.org/ 24 Libuv event loop Stack Node Thread Pool API OS console.log("hello node"); setTimeout(() => { console.log("second Hello"); }, 3000); fs.createReadStream("kepler_data.csv") Timer Task Queue.on("data", (data) => { console.log("file data: ", data)); I/O Task Queue }.on("end", () => console.log("end")) Immediate Task Queue.on("error", (error) => { Event Loop console.log("error : ", error); Close Task Queue }); console.log("bye node"); https://libuv.org/ 25 Libuv event loop console.log('cc node'); setTimeout(function () { for (let i=1; i< 100000; i++) { console.log('procssing',i); } console.log('end processing :D'); },0); console.log('bye node'); 26 Libuv event loop  Afin de bien travailler avec l’event loop éviter :  Le calcul complexe et couteux en CPU  Les objets JSON lourd  Le expressions régulières complexes. https://libuv.org/ 27 C’est quoi Angular? 28 C’est quoi Angular? Framework JS SPA Supporte plusieurs langages : ES5, EC6, TypeScript, Dart Rapide Orienté Composant 29 Est-ce qu’Angular est stable ????? 30 SPA Application Web C traditionnelle H T J S M L S S H C T J M S L S S H C T J M S L S S C S C S JS S H S T H JS M T M L SPA L API 31 Angular : Arbre de composants 32 Architecture Angular 33 Principaux concepts et notions Component Template DataBinding Méta données Injection de Service Route dépendance 34 Les librairies d’Angular  Ensemble de modules JS Des librairies qui contiennent un ensemble de fonctionnalités. Toutes les librairies d’Angular sont préfixées par @angular Récupérable à travers un import JavaScript. Exemple pour récupérer l’annotation component : import { Component } from '@angular/core'; 35 Les composants  Le composant est la partie principale d’Angular. Un composant s’occupe d’une partie de la vue. L’interaction entre le composant et la vue se fait à travers une API. 36 Template Un Template est le complément du composant. C’est la vue associée au composant. Elle représente le code HTMl géré par le composant. 37 Les méta data  Appelé aussi « decorator », ce sont des informations permettant de décrire les classes.  @Component permet d’identifier la classe comme étant un composant angular. 38 Le Data Binding  Le data binding est le mécanisme qui permet de mapper des éléments du DOM avec des propriétés et des méthodes du composant. Le Data Binding permettra aussi de faire communiquer les composants. 39 Les directives  Lesdirectives Angular sont des classes avec la métadata @Directive. Elle permettent de modifier le DOM et de rendre les Template dynamiques. Apparaissent dans des éléments HTML comme les attributs. Un composant est une directive à laquelle Angular a associé un Template. Ils existe deux autres types de directives : Directives structurelles Directive d’attributs 40 Les services  Classes permettant d’encapsuler des traitements métiers. Doivent être légers. Associées aux composants et autres classes par injection de dépendances. 41 Installation d’Angular Deux méthodes pour installer un projet Angular.  Cloner ou télécharger le QuickStart seed proposé par Angular. Utiliser le Angular-cli afin d’installer un nouveau projet (conseillé). Remarque : L’installation de NodeJs est obligatoire afin de pouvoir utiliser son npm (Node Package Manager). 42 Installation d’Angular QuickStart Deux méthodes  Télécharger directement le projet du dépôt Git https://github.com/angular/quickstart  Ou bien le cloner à l’aide de la commande suivante : git clone https://github.com/angular/quickstart.git quickstart  Se positionner sur le projet Installer les dépendance à l’aide de npm : npm install  lancer le projet à l’aide de npm : npm start 43 Installation d’Angular Angular Cli  Nous allons installer notre première application en utilisant angular Cli.  Si vous avez Node c’est bon, sinon, installer NodeJs sur votre machine. Vous devez avoir une version de node >= 14.2  Une fois installé vous disposez de npm qui est le Node Package Manager. Afin de vérifier si vous avez NodeJs installé, tapez npm –v.  Installer maintenant le Cli en tapant la : npm install -g @angular/cli  npm install -g @angular/[email protected] installe la version 16.2.15  npm view @angular/cli affiche la liste des versions de la cli  Installer un nouveau projet à l’aide de la commande ng new nomProjet  npx @angular/[email protected] new nomProjet  Afin d’avoir du help pour le cli tapez ng help  Lancer le projet en utilisant la commande ng serve 44 Angular versions 45 Installation d’Angular Angular Cli Positionnez vous maintenant dans le dossier Tapez la commande suivante : ng new nomNewProject  lancez le projet à l’aide de npm : ng serve Naviguez vers l’adresse mentionnée.  Vous pouvez configurer le Host ainsi que le port avec la commande suivante : ng serve --host leHost --port lePort Pour plus de détails sur le cli visitez https://cli.angular.io/ 46 Quelques commandes du Cli Commande Utilisation Component ng g component my-new-component Directive ng g directive my-new-directive Pipe ng g pipe my-new-pipe Service ng g service my-new-service Class ng g class my-new-class Interface ng g interface my-new-interface Module ng g module my-module 47 Arborescence d’un projet Angular Application moduless Application modulaire 48 Ajouter Bootstrap On peut ajouter Bootstrap de plusieurs façons : 1- Via le CDN à ajouter dans le fichier index.html 2- En le téléchargeant du site officiel 3- Via npm ◦ Npm install bootstrap --save 49 Ajouter Bootstrap Pour ajouter les dossiers téléchargés on peut le faire de deux façons : 1- En l’ajoutant dans index.html 2- En ajoutant le chemin des dépendances dans les tableaux styles et scripts dans le fichier angular.json: "styles": [ "../node_modules/bootstrap/dist/css/bootstrap.min.css", "styles.css", ], "scripts": [ "../node_modules/bootstrap/dist/js/bootstrap.min.js" ], 50 Ajouter Bootstrap Ajouter dans le fichier src/style.css un import de vos bibliothèques. @import "./../node_modules/bootstrap/"; Essayer la même chose avec font-awesome. 51 Angular Les composants AYMEN SELLAOUTI 52 Objectifs 1. Comprendre la définition du composant 2. Assimiler et pratiquer la notion de Binding 3. Gérer les interactions entre composants. 53 Qu’est ce qu’un composant (Component)  Un composant est une classe qui permet de gérer une vue. Il se charge uniquement de cette vue la. Plus simplement, un composant est un fragment HTML géré par une classe JS (component en angular et controller en angularJS)  Une application Angular est un arbre de composants  La racine de cet arbre est l’application lancée par le navigateur au lancement.  Un composant est :  Composable (normal c’est un composant)  Réutilisable  Hiérarchique (n’oublier pas c’est un arbre) NB : Dans le reste du cours les mots composant et component représentent toujours un composant Angular. 54 Angular : Arbre de composants 55 Quelques exemples 56 Quelques exemples 57 Quelques exemples 58 Quelques exemples 59 Quelques exemples 60 Quelques exemples 61 Premier Composant Le décorateur @Component permet d’ajouter un @Component({ comportement à notre classe et de spécifier que c’est un selector: "app-root", Composant Angular. standalone: true, selector permet de spécifier le tag (nom de la balise) imports: [RouterOutlet, RouterLink], associé ce composant templateUrl: "./app.component.html", standalone permet de spécifier si le composant est standalone ou pas styleUrl: "./app.component.css", imports L’ensemble des dépendances du composant }) templateUrl: spécifie l’url du template associé au export class AppComponent { composant title = "ng18"; styleUrls: tableau des feuilles de styles associé à ce } composant 62 Création d’un composant  Deux méthodes pour créer un composant Manuelle Avec le Cli  Cli, Avec la commande ng generate component my-new-component ou son raccourci ng g c my-new-component 63 Création d’un composant  La commande generate possède plusieurs options OPTION DESCRIPTION --inlineStyle=true|false Inclus les styles css dans le composant Aliases: -s --inlineTemplate=true|false Inclus le template dans le composant Aliases: -t --prefix=prefix Le préfixe à appliquer pour la génération des composants Valeur par défaut: app Aliases: -p https://v17.angular.io/cli/generate#component-command 64 Property Binding Balises Attributs Evènement Attributs Méthodes HTML TS 65 Property Binding @Component({ selector: 'app-color', templateUrl: './color.component.html', styleUrls: ['./color.component.css'], providers: [PremierService] Color }) export class ColorComponent implements OnInit { color = 'red'; processReq(message: any) { le contenu de la propriété color est {{color}} alert(message); log data } loggerMesData() { Go to Cv this.premierService.logger('test'); } HTML goToCv() { const link = ['cv']; this.router.navigate(link); } TS 66 Property Binding  Binding unidirectionnel.  Permet aussi de récupérer dans le DOM des propriétés du composant.  La propriété liée au composant est interprétée avant d’être ajoutée au Template.  Deux possibilités pour la syntaxe:  [propriété], exemple [hidden]=false  bind-propriété, exemple bind-hidden=false 67 Event Binding  Binding unidirectionnel.  Permet d’interagir du DOM vers le composant. L’interaction se fait à travers les événements. Deux possibilités pour la syntaxe :  (evenement), exemple (click)=changeBehavior()  on-evenement 68 Property Binding et Event Binding import { Component } from '@angular/core'; @Component({ selector: 'inter-interpolation', Nom : {{nom}} template : `interpolation.html` , Age : {{age}} styles: [] Adresse : {{adresse}} }) export class InterpolationComponent { //Property Binding nom:string ='Aymen Sellaouti'; adresse:string ='Chez moi ou autre part :)'; getName(){ //Event Binding return this.nom; Modifier le nom this.nom=newName; } } Component Template 69 Exercice  Créer un nouveau composant. Ajouter y un Div et un input de type texte.  Fait en sorte que lorsqu’on écrive une couleur dans l’input, ca devienne la couleur du Div.  Ajouter un bouton. Au click sur le bouton, il faudra que le Div reprenne sa couleur par défaut.  Ps : pour accéder au contenu d’un élément du Dom utiliser #nom dans la balise et accéder ensuite à cette propriété via le nom.  Pour accéder à une propriété de style d’un élément on peut binder la propriété [style.nomPropriété] exemple [style.backgroundColor] 70 Two way Binding  Binding Bi-directionnel  Permet d’interagir du Dom ver le composant et du composant vers le DOM. Se fait à travers la directive ngModel ( on reviendra sur le concept de directive plus en détail) Syntaxe : [(ngModel)]=property Afin de pouvoir utiliser ngModel vous devez importer le FormsModule dans app.module.ts 71 Property Binding et Event Binding import { Component} from '@angular/core'; @Component({ Change me if u can selector: 'app-two-way', 0 et currentValue + 1); précédente. setCounter(val: number) { this.counter.set(val); } } 110 Exercice  Reprenez L’exercice ‘ColorComponent’ en utilisant les signaux. 111 computed() L’api computed() permet de créer un nouveau signal dont la valeur dépend d’autres signaux. Lorsqu'un signal est mis à jour, tous ses signaux dépendants seront alors automatiquement mis à jour. On note que computed() retourne un objet de type Signal et non WritableSignal. lastname = signal('aymen'); firstname = signal('sellaouti'); fullname = computed(() => `${this.firstname()} ${this.lastname()}`) 112 computed() Pour identifier un signal qui a changé, et donc si on doit exécuté un computed, Angular utilise Object.is. Object.is() permet de déterminer si deux valeurs sont identiques. Deux valeurs sont considérées identiques si : elles sont toutes les deux undefined elles sont toutes les deux null elles sont toutes les deux true ou toutes les deux false elles sont des chaînes de caractères de la même longueur et avec les mêmes caractères (dans le même ordre) elles sont toutes les deux le même objet (même référence) elles sont des nombres et sont toutes les deux égales à +0 sont toutes les deux égales à -0 sont toutes les deux égales à NaN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is 113 computed() Comment ca marche ? @Component({ template: ` L’arbre de dépendance est Counter value {{ counter() }} crée dynamiquement à Derived counter: {{ derivedCounter() }} Increment chaque appel du computed. Set multiplier to 10 `,}) export class ComputedProblemComponent { Il faut donc faire très counter = signal(0); multiplier: number = 0; attention dans la définition derivedCounter = computed(() => { de vos computed lorsqu’il y a if (this.multiplier < 10) { return 0; des traitement conditionnel. } else { return this.counter() * this.multiplier; } }); increment() { console.log(`Updating counter...`); this.counter.set(this.counter() + 1); } } https://blog.angular-university.io/angular-signals/ 114 computed() Exclure un signal de l’arbre de dépendence Si pour une raison ou une autre vous voulez lire une valeur d’un signal dans un comptued mais sans l’intégrer dans l’arbre de dépendance, vous pouvez utiliser l’Api untracked. Dans cet exemple le computed fullname ne sera mis à jour que si le signal firstname change lastname = signal('sellaouti'); firstname = signal('aymen'); fullname = computed(() => `${this.firstname()} ${untracked(this.lastname)}`); 115 computed() Modifier un signal dans un computed  La fonction computed doit être sans effets de bord, ce qui signifie qu'elle ne doit accéder qu'aux valeurs des signaux dépendants (ou à d'autres valeurs impliquées dans le calcul) et éviter toute mise à jour. Vous ne pouvez pas modifier un signal dans un computed, ceci provoquera une erreur. fullname = computed(() => { console.log('i am computing....'); this.firstname.set('ccc'); return `${this.firstname()} ${untracked(this.lastname)}`; }); 116 computed() Les computed, autres propriétés Les computed sont paresseux (lazy), ce qui signifie que computed n'est invoquée que lorsque quelqu'un s'intéresse (lit) sa valeur. Cela permet d'optimiser les performances en évitant les calculs inutiles.  Les computed sont automatiquement supprimés lorsque la référence du signal calculée devient hors de portée. Cela garantit que les ressources sont libérées et qu’aucune opération de nettoyage explicite n’est requise.  Ceci est due à l’utilisation des weakRefrence avec les signaux https://en.wikipedia.org/wiki/Weak_reference 117 Writablesignals et signals Par défaut, tous les signaux créés par la fonction Signal sont de type WritableSignal. Ainsi, n’importe quelle entité peut modifier sa valeur (via les méthodes set() et update()). Si on désire interdire toute modification de la valeur d’un signal, Angular nous propose la méthode asReadOnly(). Les signaux créés par computed sont, par défaut, read only. private currencies = signal(['USD', 'EUR', 'GBP']); currencies$ = this.currencies.asReadonly(); 118 Exercice  Créer un composant TTC qui permet de calculer le prix TTC d’un produit selon le nombre de pièces et la TVA. Sachant que l’utilisateur peut changer toutes les valeurs et que par défaut la quantité est de 1 le prix est de 0 et la tva est de 18.  Si le nombre de pièces est entre 10 et 15 une remise de 20% est appliquée.  Si le nombre de pièces est supérieur à 15 une remise de 30% est appliquée. 119 L’API effect() Dans certains cas d’utilisation, vous avez besoin d’être notifié par le changement d’un signal pour effectuer un effet de bord, donc faire un traitement sans pour autant créer un nouveau signal ou en modifier d’autres. Pensez à un log, à un calcul d’un nombre de click, faire un appel à une API pour enregistrer une valeur,… L’API effect est la afin de vous donner cette possibilité L’effect va être réexécuté si l’un des signaux qu’il utilise émet une nouvelle valeur. 120 L’API effect() Vous pouvez créer un effet via la fonction effect. Les effets s'exécutent toujours au moins une fois. Lorsqu'un effet est exécuté, il suit tous les signaux qu’il contient. Chaque fois que l'une de ces valeurs de signal change, l'effet se reproduit. L’effet est semblable aux computed, les effets gardent une trace de leurs dépendances de manière dynamique et ne suivent que les signaux qui ont été lus lors de l'exécution la plus récente. constructor() { private logEffect = effect(() => { effect(() => { console.log(` console.log(`count:${this.counter()}`); The current count is:${this.counter()} }); `); } }); 121 L’API effect() Les effets s'exécutent toujours de manière asynchrone, pendant le export class EffectComponent { processus de change detection. counter = signal(0); constructor() { Les effets seront exécutés le nombre this.counter.set(1); this.counter.set(2); minimum de fois. Si un effet dépend } de plusieurs signaux et que plusieurs private logEffect = effect(() => { d'entre eux changent simultanément, console.log(` une seule exécution de l'effet sera The current count is: ${this.counter()}`); programmée. }); Remarque : l'API effect() est toujours en } aperçu développeur (17.3). 122 L’API effect() Un effect doit être définit dans un contexte d’injection. Ceci est faisable dans un component, un pipe, une directive ou le constructeur d’un service.  Vous pouvez aussi injecter l’Injector et le passer à l’effect en deuxième paramètre qui représente un objet d’options. private logEffectWithInjector = effect(() => { console.log( `The current count is: ${this.counter()}` ); }, { injector: this.injector } ); 123 effect() Exclure un signal de l’arbre de dépendence Si pour une raison ou une autre vous voulez lire une valeur d’un signal dans un effect mais sans l’intégrer dans l’arbre de dépendance, vous pouvez utiliser l’Api untracked. Untracked peut prendre en paramètre une fonction export declare function untracked(nonReactiveReadsFn: () => T): T; 124 Cycle de vie d’un composant  Le composant possède un cycle de vie géré par Angular. En effet, Angular : Crée le composant L’affiche Crée ses fils Les affiche Ecoute le changement des propriétés Le détruit avant de l’enlever du DOM https://medium.com/bhargav-bachina-angular-training/angular-understanding-angular-lifecycle-hooks-with-a-sample-project-375a61882478 125 Comment ca marche réellement 1. Angular lance l’application 2. Ils crée les classes pour chaque composant, il lance donc le Constructeur de mon-app component. 3. Il gère toutes les dépendances injectées au niveau du constructeur et les définit comme des paramètres 4. Il crée le nœud du Dom qui va héberger le composant 5. Il commence ensuite la création du composant fils et appelle son constructeur. Ici la propriété binded n’est pas prise en considération par Angular. 6. A ce moment Angular lance le processus de détection des changements. C’est ici qu’il mettra à jour le binding de mon-App et lancera l’appel à ngOnInit, suivi de la gestion du binding de compo-fils puis l’appel de son ngOnInit. 126 Interfaces de gestion du cycle de vie d’un composant  Afin de gérer le cycle de vie d’un composant, Angular nous offre un ensemble d’interfaces à implémenter pour les différentes étapes du cycle de vie. L’ensemble des interfaces est disponible dans la librairie core d’Angular Chaque interface offre une seule méthode dont le nom suit la convention suivante : ng + NomDeL’Interface Exemple : Pour l’interface OnInit nous avons la méthode ngOnInit 127 128 129 Interfaces de gestion du cycle de vie d’un composant  ngOnChanges: Cette méthode est appelée lors d’un binding d’une propriété d’une directive. La méthode reçoit en paramètre un objet représentant les valeurs actuelles et les valeurs précédentes disponibles pour ce composant. Elle est appelé si un composant possède des input (@Input) et à chaque fois qu’elles changent.  ngOnInit: Cette méthode initialise le composant après qu’Angular ait initialisé les propriétés du composant.  ngDoCheck: Appelé après chaque change détection. 130 Interaction entre composants Parent Enfant [propertyBinding] @Input Component Component (eventBinding) Template @Output Template 131 Pourquoi ? Le père voit le fils, le fils ne voit pas le père Parent import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` Enfant Je suis le composant père `, styles: }) export class AppComponent { title = 'app works !'; } 132 Interaction du père vers le fils Le père peut directement envoyer au fils des données par Property Binding Parent import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` Enfant Je suis le composant père `, styles: }) export class AppComponent { title = 'app works !'; } 133 Interaction du père vers le fils Problème : Le père voit le fils mais pas ces propriétés !!! Solution : les rendre visible avec Input Parent import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` Enfant Je suis le composant père `, styles: }) export class AppComponent { title = 'app works !'; } 134 Interaction du père vers le fils Problème : Le père voit le fils mais pas ces propriétés !!! Solution : les rendre visible avec Input import { Component } from Parent '@angular/core'; import {Component, Input} from '@angular/core'; @Component({ selector: 'app-root', @Component({ template: ` selector: 'app-input', Enfant Je suis le composant père templateUrl: './input.component.html', styleUrls: `, ['./input.component.css'] styles: }) }) export class InputComponent export class AppComponent { { title = 'app works !'; @Input() external:string; } } 135 Two way Binding [(ngModel)] 136 Signal Input  Pour que l’exemple précédent fonctionne, on avait deux méthodes :  Utiliser un setter  Utiliser le OnChange hook  La version 17.1 a vu Angular introduire le concept de Signal Input pour améliorer l’interaction entre les composants.  Les Signal Input permettent de lier les valeurs des composants parents. Ces valeurs sont exposées à l'aide d'un signal et peuvent changer au cours du cycle de vie de votre composant. import { Input, input } from '@angular/core'; isEvenn!: boolean; // Sans Signal Input @Input() isEven: number; // Avec les signal Input counter = input(); 137 Signal Input  Les Signal Input permettent d’exposer des // optional paramètres au composant parent afin qu’il counter = input(); puisse paramétrer le composant fils. // Required counter = input.required();  Les Signal Input sont en lecture seule. // Valeur par défaut = 0 Seul Angular peut changer leur valeur suite à counter = input.required(0); un changement côté parent.  Le Signal Input peut être optionnel ou counter = input(0,{ required alias: 'counter', transform: (value: number) => value * 100,  Il peut avoir une valeur par défaut });  Il peut avoir une Alias counter = input.required({ alias: 'counter',  Et vous pouvez le transformer transform: (value: number) => value * 100, }); 138 Exercice  Créer un composant fils  Récupérer la couleur du père dans le composant fils  Faite en sorte que le composant fils affiche la couleur du background de son père 139 Interaction du fils vers le père L’enfant ne peut pas voir le parent. Appel de l’enfant vers le parent. Que faire ? Parent import {Component} from '@angular/core'; @Component({ selector: 'bind-output', Enfant template: `Bonjour je suis le fils`, styleUrls: ['./output.component.css'] }) export class OutputComponent { valeur:number=0; } } 140 Interaction du fils vers le père Solution : Pour entrer c’est un input pour sortir c’est surement un output. Externaliser un évènement en utilisant l’Event Binding. import {Component, EventEmitter, Output} from '@angular/core'; Parent @Component({ selector: 'bind-output', template: ` + `, styleUrls: ['./output.component.css'] Enfant }) export class OutputComponent { valeur:number=0; // On déclare un evenement @Output() valueChange=new EventEmitter(); Au click sur l’event incrementer(){ valueChange je vais this.valeur++; emmètre une réponse this.valueChange.emit contenant ce que je veux this.valeur); } envoyer à mon père }} 141 Interaction du père vers le fils La variable $event est la variable utilisée pour faire transiter les informations. import {Component, EventEmitter, Output} from import { Component } from '@angular/core'; '@angular/core'; Parent @Component({ @Component({ selector: 'bind-output', selector: 'app-root', template: ` template: ` + `, {{result}} Enfant styleUrls: ['./output.component.css'] valeur:number=0; `, Mon père va ensuite // On déclare un evenement styles: [``], @Output() valueChange=new EventEmitter(); }) intercepter l’event et export class AppComponent { incrementer(){ récupérer ce que je lui this.valeur++; title = 'app works !'; ai envoyé à travers la this.valueChange.emit( result:any='N/A'; variable $event et va this.valeur showValue(value){ l’utiliser comme il veut ); this.result=value; } } }} } Parent Enfant 142 Signal Output  L'API output() remplace directement le décorateur @Output() traditionnel.  Le décorateur @Output n’est pas obsolète  Angular a donc ajouté output() comme nouvelle façon de définir les sorties des composants dans Angular, d'une manière plus sûre et mieux intégrée à RxJ que l'approche traditionnelle @Output et EventEmitter.  La syntaxe a été simplifiée. @Output() oldSelectCv = new EventEmitter(); selectCv = output(); onClick() { Pere if (this.cv) { this.selectCv.emit(this.cv); } Fils 143 Exercice  Ajouter une variable myFavoriteColor dans le composant du fils.  Ajouter un bouton dans le composant Fils  Au click sur ce bouton, la couleur de background du Div du père doit prendre la couleur favorite du fils. 144 Exercice  Le but de cet exercice est de AppComponent créer une mini plateforme de CvComponent ListeComponent recrutement. DetailComponent  La première étape est de créer ItemComponent la structure suivante avec une vue contenant deux parties :  Liste des Cvs inscrits  Détail du Cv qui apparaitra au click  Il vous est demandé juste d’afficher un seul Cv et de lui afficher les détails au click. Il faudra suivra cette architecture. 145 Exercice  Le but de cet exercice est de créer une mini plateforme de recrutement.  La première étape est de créer la structure suivante avec une vue contenant deux parties :  Liste des Cvs inscrits  Détail du Cv qui apparaitra au click  Il vous est demandé juste d’afficher un seul Cv et de lui afficher les détails au click. Il faudra suivra cette architecture. 146 Exercice AppComponent CvComponent ListeComponent DetailComponent ItemComponent 147 Exercice AppComponent CvComponent ListeComponent DetailComponent ItemComponent Au click sur le Cv les détails sont affichés 148 Exercice Un cv est caractérisé par : id name firstname Age Cin Job path Au click sur le Cv les détails sont affichés 149 Angular Les directives AYMEN SELLAOUTI 150 Plan du Cours 1. Introduction 2. Les composants 3. Les directives 3 Bis. Les pipes 4. Service et injection de dépendances 5. Le routage 6. Form 7. HTTP 8. Les modules 9. Les tests unitaires 151 Objectifs 1. Comprendre la définition et l’intérêt des directives. 2. Voir quelques directives d’attributs offertes par angular et savoir les utiliser 3. Créer votre propre directive d’attributs 4. Voir quelques directives structurelles offertes par angular et savoir les utiliser 152 Qu’est ce qu’une directive  Une directive est une classe permettant import { Directive } from '@angular/core'; d’attacher un comportement aux éléments du DOM. Elle est décorée @Directive({ avec l’annotation @Directive. selector: '[appHighlight]', standalone: true })  Apparait par défaut dans un élément export class HighlightDirective { comme un tag (comme le font les attributs). constructor() { }  La command pour créer une directive est }  ng g d nomDirective Bonjour je teste une directive 153 Qu’est ce qu’une directive  La documentation officielle d’Angular identifie trois types de directives :  Les composants qui sont des directives avec des templates.  Les directives structurelles qui changent l’apparence du DOM en ajoutant et supprimant des éléments.  Les directives d’attributs (attribute directives) qui permettent de changer l’apparence ou le comportement d’un élément. 154 Les directives d’attribut (ngStyle)  Cette directive permet de modifier l’apparence de l’élément cible.  Elle est placé entre [ ] [ngStyle]  Elle prend en paramètre un attribut représentant un objet décrivant le style à appliquer.  Elle utilise le property Binding. 155 Les directives d’attribut (ngStyle) import { Component} from import { Component} from '@angular/core'; '@angular/core'; @Component({ @Component({ selector: 'direct-direct', selector: 'direct-direct', template: ` template: ` styles: [` h1 { font-weight: normal; } p{color:yellow;background-color: red} `, `], styleUrls: ['./direct.component.css'] }) }) export class AppComponent { export class DirectComponent{ private myfont:string="garamond"; } @Input() private myColor:string="red"; private myBackground:string="blue" } 158 Les directives d’attribut (ngStyle) 159 Exercice  Nous voulons simuler un Mini Word pour gérer un paragraphe en utilisant ngStyle.  Préparer un input de type texte, un input de type number, et un select box.  Faite en sorte que lorsqu’on écrive une couleur dans le texte input, ca devienne la couleur du paragraphe. Et que lorsque on change le nombre dans le number input la taille de l’écriture.  Finalement ajouter une liste et mettez y un ensemble de police. Lorsque le user sélectionne une police dans la liste, la police dans le paragraphe change. 160 Les directives d’attribut (ngClass)  Cette directive permet de modifier l’attribut class.  Elle cohabite avec l’attribut class.  Elle prend en paramètre  Une chaine (string)  Un tableau (dans ce cas il faut ajouter les [ ] donc [ngClass]  Un objet (dans ce cas il faut ajouter les [ ] donc [ngClass]  Elle utilise le property Binding. 161 Les directives d’attribut (ngClass) import {Component, Input} from '@angular/core'; // Tableau @Component({ template: ` // Objet test ngClass styles: [`.encadrer{ border: inset 3px black; }.colorer{ color: blueviolet; }.arrierplan{background-color: salmon; } `] }) export class DirectComponent{ private myfont:string="garamond"; @Input() private myColor:string="red"; private myBackground:string="blue« private isColoree:boolean=true; private isArrierPlan:boolean=true } 162 Exercice  Préparer 3 classes présentant trois thèmes différents (couleur font-size et font-police)  Au choix du thème votre cible changera automatiquement 163 Customiser un attribut directive  Afin de créer sa propre « attribut directive » il faut utiliser un HostBinding sur la propriété que vous voulez binder.  Exemple : @HostBinding('style.backgroundColor') bg:string="red";  Si on veut associer un événement à notre directive on utilise un HostListner qu’on associe à un événement déclenchant une méthode.  Exemple : @HostListener('mouseenter') mouseover(){ this.bg =this.highlightColor; } Afin d’utiliser le HostBinding et le HostListner il faut les importer du core d’angular 164 Exercice Un truc plus sympas on va créer un simulateur d’écriture arc en ciel. Créer une directive Créer un hostbinding sur la couleur et la couleur de la bordure. Créer un tableau de couleur dans votre directive. Faite en sorte qu’en appliquant votre directive à un input, à chaque écriture d’une lettre (event keyup) la couleur change en prenant aléatoirement l’une des couleurs de votre tableau. Pensez à utiliser Math.random() qui vous retourne une valeur entre 0 et 1. 165 Exercice 166 Customiser une attribut directive  Nous pouvons aussi utiliser le input afin de rendre notre directive paramétrable  Tous les paramètres de la directive peuvent être mises en input puis récupérer à partir de la cible.  Exemple  Dans la directive @Input() private myColor:string="red";  167 Les directives structurelles  Une directive structurelle permet de modifier le DOM.  Elles sont appliquées sur l’élément HOST.  Elles sont généralement précédées par le préfix *.  Les directives les plus connues sont :  *ngIf  *ngFor  [ngSwitch] 168 Les directives structurelles *ngIf  Prend un booléen en paramètre.  Si le booléen est true alors l’élément host est visible  Si le booléen est false alors l’élément host est caché Exemple Je suis visible :D Le *ngIf c'est faché contre moi et m'a caché :( 169 Exercice Teston *ngIf en créant un composant contenant un bouton et un paragraphe. Le bouton s’appellera ‘Click moi’ Un paragraphe contenant une phrase Au click, si le paragraphe est caché on l’affiche, s’il est affiché, on le cache 170 Les directives structurelles *ngFor  Permet de répéter un élément plusieurs fois dans le DOM.  Prend en paramètre les entités à reproduire. {{episode.title}}  Fournit certaines valeurs :  index : position de l’élément courant  first : vrai si premier élément Episode {{i+1}}{{episode.title}} 171 Angular Les pipes AYMEN SELLAOUTI 172 Références 173 Plan du Cours 1. Introduction 2. Les composants 3. Les directives 3 Bis. Les pipes 4. Service et injection de dépendances 5. Le routage 6. Form 7. HTTP 8. Les modules 9. Les tests unitaires 174 Objectifs 1. Définir les pipes et l’intérêt de les utiliser 2. Vue globale des pipes prédéfinies 3. Créer un pipe personnalisé 175 Qu’est ce qu’un pipe Un pipe est une fonctionnalité qui permet de formater et de transformer vos données avant de les afficher dans vos Templates. Exemple l’affichage d’une date selon un certain format. Il existe des pipes offerts par Angular et prêt à l’emploi. Vous pouvez créer vos propres pipes. Avec le pipe uppercase : {{pipeVar|uppercase}} Sans aucun pipe : {{pipeVar}} 176 Syntaxe  Afin d’utiliser un pipe vous utilisez la syntaxe suivante :  {{ variable | nomDuPipe }}  Exemple : {{ maDate | date }}  Afin d’utiliser plusieurs pipes combinés vous utilisez la syntaxe suivante :  {{ variable | nomDuPipe1 | nomDuPipe2 | nomDuPipe3 }}  Exemple : {{ maDate | date | uppercase }} 177 Les pipes disponibles par défaut (Built-in pipes)  La documentation d’angular vous offre la liste des pipes prêt à l’emploi. https://angular.io/api?type=pipe  uppercase  lowercase  titlecase  currency  date  json  percent  … 178 Paramétrer un pipe  Afin de paramétrer les pipes ajouter ‘:’ après le pipe suivi de votre paramètre.  {{ maDate | date:"MM/dd/yy" }}  Si vous avez plusieurs paramètres c’est une suite de ‘:’  {{ nom | slice:1:4 }} 179 Pipe personnalisé  Un pipe personnalisé est une classe décoré avec le décorateur @Pipe.  Elle implémente l’interface PipeTransform  Elle doit implémenter la méthode transform qui prend en paramètre la valeur cible ainsi qu’un ensemble d’options.  La méthode transform doit retourner la valeur transformée  Le pipe doit être déclaré au niveau de votre module de la même manière qu’une directive ou un composant.  Pout créer un pipe avec le cli : ng g p nomPipe 180 Exemple de pipe import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ {{team | team}} name: 'team’, standalone: true, }) export class TeamPipe implements PipeTransform { ngOnInit() { transform(value: any, args?: any): any { this.teams = ['milan', 'barca', 'roma']; switch (value) { } case 'barca' : return ' blaugrana'; case 'roma' : return ' giallorossa'; case 'milan' : return ' rossoneri'; } } } 181 Pipe pure et impure  Par défaut un pipe t considéré comme une fonction pure  Une fonction est dite pure si elle :  Ne provoque pas de side effect.  Renvoie la même valeur pour les mêmes paramètres.  Lorsque le pipe est pur, la méthode transform() est invoquée uniquement lorsque ses arguments d'entrée changent. @Pipe({ name: ‘myPipe’, standalone: true, pure: true }) 182 Exercice  Créer un composant contenant un input de type texte et une ol  A chaque fois que vous écrivez dans l’input, afficher le contenu dans un paragraphe (utilisez ngModel).  Dans le composant initialiser un tableau avec 100 valeurs entre 20 et 30.  Dans le ol afficher la valeur de chacun des éléments du tableau et en faça la valeur de cet élément lorsque on lui applique la fonction suivante:  f(x) = 2f(x-1) + 3f(x-2) si n> 1 et f(n) = 1 si n== 0 ou 1  Tester l’input. Que remarquez vous lorsque vous écrivez dans l’input ? 183 Memo  Il existe une bibliothèque memo-decorator qui permet de mémoriser des fonctions pures.  Elle permet en l’utilisant de cacher les résultats des fonctions pures et de les réutiliser.  Pour l’installer utiliser la commande npm i memo-decorator import memo from 'memo-decorator'; @memo() pureFonction(n: number): number {//…} 184 Exercice  Utilisez les pipes et utiliser la bibliothèque memo pour optimiser votre pipe 185 Exercice Créer un pipe appelé defaultImage qui retourne le nom d’une image par défaut que vous stockerez dans vos assets au cas ou la valeur fournie au pipe est une chaine vide ou ne contient que des espaces. 186 Angular Service et injection de dépendances AYMEN SELLAOUTI 187 Références 188 Plan du Cours 1. Introduction 2. Les composants 3. Les directives 3 Bis. Les pipes 4. Service et injection de dépendances 5. Le routage 6. Form 7. HTTP 8. Les modules 9. Les tests unitaires 189 Objectifs 1. Définir un service 2. Définir ce qu’est l’injection de dépendance 3. Injecter un service 4. Définir la portée d’un service 5. Réordonner son code en utilisant les services 190 Qu’est ce qu’un service ? Un service est une classe qui permet d’exécuter un traitement. Permet d’encapsuler des fonctionnalités redondantes permettant ainsi d’éviter la redondance de code. Component 1 Component 2 Component 3 f(){}; f(){}; f(){}; g(){}; g(){}; g(){}; k(){}; l(){}; m(){}; Redondance de code Maintenabilité difficile 191 Qu’est ce qu’un service ? f(){}; g(){}; Component 1 Component 2 Component 3 k(){}; l(){}; m(){}; 192 Qu’est ce qu’un service ? Un service est un médiateur entre la vue et la logique Fournit un ensemble de fonctionnalités 193 Qu’est ce qu’un service ? Un service peut donc : Interagir avec les données (fournit, supprime et modifie) Interaction entre classes et composants Tout traitement métier (calcul, tri, extraction …) 194 Création d’un service  Via CLI  ng generate service nomDuService  ng g s nomDuService 195 Premier Service import { Injectable } from '@angular/core'; @Injectable() export class FirstService { constructor() { } } 196 Injection de dépendance (DI)  L’injection de dépendance est un patron de conception. Classe A1{ Classe A2{ Classe A3{ ClasseB b; ClasseB b; ClasseC c; ClasseC c; … … … } } }  Que se passera t-il si on change quelque chose dans le constructeur de B ou C ?  Qui va modifier l’instanciation de ces classes dans les différentes classes qui en dépendent? 197 Injection de dépendance (DI)  Déléguer cette tache à une entité tierce. Classe A1{ Classe A2{ Classe A3{ Constructor(B b, C c) Constructor(B b) Constructor(C c) … … … } } } INJECTOR 198 Injection de dépendance (DI) 199 Injection de dépendance (DI)  Comment les injecter ?  Comment spécifier à l’injecteur quel service et ou est-il visible ? 200 Injection de dépendance (DI)  L’injection de dépendance utilise les étapes suivantes :  Déclarer la dépendance dans le provider du module ou du composant  Passer la dépendance comme paramètre du constructeur de l’entité qui en a besoin. 201 Injection de dépendance (DI) Que peut on injecter  Toute dépendance de votre classe, à savoir :  Des instances de classes  Des constantes 202 Injection de dépendance (DI) Avantages  L’intérêt de l’injection de dépendance est donc :  Couplage lâche  Facilement remplacer une implémentation d'une dépendance à des fins de test  Prendre en charge plusieurs environnements d'exécution  Fournir de nouvelles versions d'un service à un tiers qui utilise votre service dans sa base de code, etc. https://blog.angular-university.io/angular-dependency-injection/ 203 Injection de dépendance (DI) Comment ca fonctionne  Injection de dépendance => Il nous faut donc une dépendance  Afin de Lier cette dépendance au système d’injection de dépendance d’Angular nous devons répondre à deux questions  Comment Angular va créer la dépendance ?  Quand est ce qu’Angular doit utiliser cette dépendance ?  Le moyen permettant de spécifier au système d’injection de dépendance d’Angular comment créer la dépendance est la fonction Provider factory.  Une Provider factory est simplement une fonction simple qu'Angular peut appeler afin de créer une dépendance. 204 Injection de dépendance (DI) Comment ca fonctionne  Cette fonction peut être créée implicitement par Angular en utilisant quelques conventions simples (le cas le plus répondu) ou par vous même.  Ceci implique que pour toute dépendance de votre application quelque soit son type, il existe une Provider Factory qui sait comment la créer et qui le fait. 205 Injection de dépendance (DI) Comment ca fonctionne function todoServiceProviderFactory(): TodoService { return new TodoService(); } function todoServiceProviderFactory(http:HttpClient): TodoService { return new TodoService(http); } 206 Injection de dépendance (DI) Associer votre Factory Provider à Angular Token  Maintenant il reste à dire à Angular quand utiliser ce provider.  Donc, nous devons répondre à cette interrogation : Comment Angular sait-il quoi injecter, et donc quelle Provider factory appeler pour créer quelle dépendance ?  Pour ce faire, vous pouvez utilisez des Tokens.  Un Token peut avoir plusieurs formes et il a pour rôle d’identifier une Provider Factory. 207 Injection de dépendance (DI) Associer votre Factory Provider à Angular Angular injection token  La première forme de Token est l’Angular injection token  C’est une instance de la class InjectionToken  Son rôle est d’identifier le service dans le système d’injection de dépendance export const TODOS_SERVICE_TOKEN = new InjectionToken("TODO_SERVICE_TOKEN"); 208 Injection de dépendance (DI) Associer votre Factory Provider à Angular Configurer le Provider  Maintenant que nous avons notre Provider Factory et notre Token, nous devons configurer Angular pour qu’ils les prennent en considération.  Ceci sera fait à travers le Provider qui n’est qu’un objet de configuration.  Il peut prend en paramètres 3 clés (pas que):  provide: qui est notre Token  useFactory: qui est notre Factory  deps: un tableau des dépendances de votre factory 209 Injection de dépendance (DI) Associer votre Factory Provider à Angular Configurer le Provider export const TODOS_SERVICE_TOKEN = new InjectionToken("TODO_SERVICE_TOKEN"); function todoServiceProviderFactory(http:HttpClient): TodoService { return new TodoService(http); } providers: [ { provide: TODOS_SERVICE_TOKEN, useFactory: todoServiceProviderFactory, deps: [HttpClient] } ] app.config.ts 210 Injection de dépendance (DI) Associer votre Factory Provider à Angular Injecter la factory  Il reste une dernière étape, à savoir comment injecter notre dépendance dans notre classe.  On utilise le décorateur @Inject au niveau du constructeur et on lui passe le Token du Provider Factory que nous voulons injecter. constructor( @Inject(TODOS_SERVICE_TOKEN) private todoService: TodoService ) {} 211 Les providers personnalisés Les autres formes de Tokens  Comme nous l’avons présenté, le Token peut avoir plusieurs formes. Parmi elles, le nom de la classe.  Le token peut être aussi une chaine de caractères, mais ceci est déconseillé afin d’éviter les collisions de noms.  Le TOKEN doit être unique pour éviter toute collision, les Provider factory sont stockés dans une map, et si le provider est simple et qu’il a le même nom, la map ne contiendra que le dernier provider défini. 212 Les providers personnalisés Les autres formes de Tokens providers: [ { provide: TodoService, useFactory: todoServiceProviderFactory, deps: [HttpClient] } ], constructor( @Inject(TodoService) private todoService: TodoService ) {} 213 Les providers personnalisés useClass  Une autre option s’offre à vous, et au lieu de spécifier la Fonction du Provider Factory avec useFactory, vous pouvez utilisez la clé useClass.  En utilisant useClass, Angular saura que la valeur que nous transmettons est un constructeur valide, qu'Angular peut simplement appeler en utilisant l’opérateur new. 214 Les providers personnalisés useClass providers: [ { provide: TodoService, useClass: TodoService, deps: [HttpClient] } ], constructor( @Inject(TodoService) private todoService: TodoService ) {} 215 Les providers personnalisés useClass  Une autre fonctionnalité très pratique de useClass est que pour ce type de dépendances, Angular essaiera de déduire le Token d'injection au moment de l'exécution en fonction de la valeur des annotations de type Typescript.  Cela signifie qu'avec les dépendances useClass, nous n'avons même plus besoin du décorateur Inject, ce qui explique pourquoi vous le voyez rarement. 216 Les providers personnalisés useClass providers: [ { provide: TodoService, Le Token est déterminé par useClass: TodoService, Angular en utilisant le Type deps: [HttpClient] TodoService } ], constructor(private todoService: TodoService) {} 217 @Injectable C’est un décorateur permettant de rendre une classe injectable Une classe est dite injectable si on peut y injecter des dépendances @Component, @Pipe, et @Directive sont des sous classes de @Injectable(), ceci explique le fait qu’on peut y injecter directement des dépendances.  Si vous n’aller injecter aucun service dans votre service, cette annotation n’est plus nécessaire. Remarque : Angular conseille de toujours mettre cette annotation. 218 Les providers personnalisés useClass  En utilisant le décorateur @Injectable, votre Provider devient encore plus simple puisqu’on n’a plus à spécifier les dépendances qui seront directement déterminé au niveau du constructeur par le Système d’Injection de dépendance d’Angular providers: [ providers: [ providers: [ { { { provide: TodoService, provide: TodoService, TodoService, useClass: TodoService, useClass: TodoService, } deps: [HttpClient] } ], } ], ], 219 Les providers personnalisés useClass  La syntaxe useClass est aussi utile pour injecter dynamiquement une classe.  Imaginez que le service de log dépend de l’environnement de développement. @Module({ export const appConfig: ApplicationConfig = { providers: [ providers: [ { { provide: LoggerService, provide: LoggerService, useClass: useClass: config.env === 'development' config.env === 'development' ? DevelopmentLoggerService ? DevelopmentLoggerService : ProductionLoggerService, : ProductionLoggerService, } } ], ], }; }) export class AppModule {} 220 Exercice  Nous supposons que votre API est encore en phase de teste ou est en maintenance. Vous voulez continuer à travailler avec votre CvComponent.  Créer un service FakeCvService  Fait en sorte d’avoir une fonction getCvs qui retourne un tableau de cvs  Dans votre cvComponent provider ce fake service à la place du vrai en vous basant sur une configuration.  Vérifier le bon fonctionnement  Remarque: pour créer un observable, vous pouvez utilisez l’opérateur de création of. 221 Les providers personnalisés multi  La plupart des dépendances de notre système correspondront à une seule valeur, comme par exemple une classe.  Cependant, il y a des occasions où nous voulons avoir plusieurs instances pour le même provider.  Pour ce faire, ajouter la clé multi et mettez la à true.  Au lieu de recevoir une instance, vous recevrez un tableau d’instance. const AuthentificationInterceptorProvider = { provide: HTTP_INTERCEPTORS, useClass: AuthentificationInterceptor, multi: true }; 222 Injection de dépendance (DI) import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class CvService { // Ce service est visible pour tout le monde constructor() { } } 223 Injection de dépendance (DI) export const appConfig: ApplicationConfig = { @Injectable({ providers: [ providedIn: 'root', CvService }) ], export class CvService {} }; 224 Standalone Component Les composants autonomes Configurez l’injection de dépendance  Afin de fournir un provider pour toute l’application, vous pouvez ajouter en deuxième paramètre de la fonction bootstrapApplication, un objet d’options.  Cet objet contient une clé providers qui prend en paramètre un tableau de providers.  Vous pouvez aussi récupérer des providers offert par un module avec la fonction importProvidersFrom(moduleCible). A partir de la version 15, vous avez certaines fonctions spécifiques pour les modules les plus utilisés comme le http avec sa fonction provideHttpClient(), ou provideRouter(APP_ROUTES). 225 Injection de dépendance (DI) import { Component, OnInit } from '@angular/core'; import {Cv} from './cv'; import {CvService} from "../cv.service"; @Component({ selector: 'app-cv', templateUrl: './cv.component.html', styleUrls: ['./cv.component.css'], providers:[CvService] // on peut aussi l’importer ici }) export class CvComponent implements OnInit { selectedCv : Cv; constructor(private monPremierService:CvService) { } ngOnInit() { } } 226 Les providers personnalisés la fonction inject (après Angular 14)  La fonction inject vous permet d’injecter un injectable.  Avant Angular 14 et à partir d’Angular 9, la fonction inject pouvait être utilisé uniquement dans la factory de l’InjectionToken ou dans le factory du @Injectable. A partir d’Angular 14, cette fonction n’est plus limitée aux factory. Vous pouvez maintenant l’utiliser dans vos composants, directives et pipes.  Le premier intérêt est le type safety avec le décorateur @Inject.  Il facilite aussi l’héritage en externalisant le dépendance du composant. 227 Chargement automatique du service  A partir de Angular 6 vous pouvez ne plus utiliser le provider du module afin de charger votre service mais le faire directement au niveau du service à travers l’annotation @Injectable et sa propriété providedIn. Vous pouvez charger le service dans toute l’application via le mot clé root.  Si vous voulez charger le service dans un module particulier vous l’importer et vous le mettez à la place de ‘root’. import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class CvService { constructor() { } } 228 Chargement automatique du service providedIn  La clé providedIn peut prendre les valeurs suivantes :  root : L'injecteur au niveau de l'application, c’est ce que vous trouvez dans la plupart des applications.  platform : Un injecteur de plateforme singleton spécial partagé par toutes les applications de la page.  any : Fournit une instance unique dans chaque module chargé d’une manière lazy tandis que tous les modules chargés en eager partagent une instance. Cette option est obsolète. providedIn?: Type | 'root' | 'platform' | 'any' | null; 229 Avantage de l’utilisation du providedIn  Permettre le Tree-Shaking des services non utilisés : Si le service n’est jamais utilisé, son code ne sera entièrement retiré du build final. 230 Exercice  Créons un service de Todo, le Model et le composant qui va avec. Un Todo est caractérisé par un nom et un contenu.  Ce service permettra de faire les fonctionnalités suivantes :  Logger un Todo  Ajouter un Todo  Récupérer la liste des Todos  Supprimer un Todo 231 Autres providers  Dans certains cas d’utilisation, l’utilisation standard des providers ne convient pas, imaginer l’un des cas suivants :  Vous souhaiter créer une instance personnalisée au lieu de laisser le container le faire pour vous.  Vous voulez injecter une bibliothèque externe  Vous voulez mocker une classe pour le teste  Vous voulez injecter des instances différentes selon le contexte …  Angular nous permet de définir des providers particuliers selon votre besoin. 232 Les providers personnalisés useValue  La syntaxe useValue est utile pour injecter  Une valeur constante,  Une bibliothèque externe  Remplacer une implémentation réelle par un objet fictif. providers: [ { useValue: [{ lundi: ‘Angular' }, { mardi: 'Still Angular' }], provide: 'TODOS_LIST', }, TodoService, ], 233 Les providers personnalisés useValue  Si vous injecter une classe, l’utilisation de l’injection via le constructeur reste d’actualité.  Sinon, pour injecter ce provider utiliser la syntaxe @Inject, qui prend en paramètre le Token. providers: [ constructor( { @Inject('TODOS_LIST') todoList, provide: 'TODOS_LIST', ){ useValue: [{ lundi: 'nestJs' }, { mardi: 'Still NestJs' }], console.log('Fake Todo List', todoList); }, } TodoService, ], @Controller('todo') export class TodoController { @Inject('TODOS_LIST') todoList; constructor() {} 234 Exercice  Provider la fonction uuid  Faite en sorte de l’utiliser dans le TodoService 235 Les providers personnalisés useExisting  Avec useExisting, vous créer un alias pour un provider déjà existant.  useExisting est aussi utile lorsque nous voulons créer un provider basé sur un autre provider existant.  Un autre cas d’utilisation est lorsque nous avons de nombreuses méthodes sur le service et que nous ne voulons en utiliser que quelques-unes. Cela aide à réduire la taille de l'interface. 236 Les providers personnalisés useExisting class CarService { export abstract class CarSizeService { getWeight(): number {...} abstract getHeight: number; abstract getWidth: number; getColor(): string {...} } getName(): string {...} getWidth(): number {...} getHeight(): number { … } getModel(): string {...} getYear(): number {...}... } providers: [{ provide: CarSizeService, useExisting: CarService}] 237 DI Hiérarchique  Dans Angular vous disposez de plusieurs endroits où vous pouvez définir les fournisseurs pour vos dépendances :  Module  Composant  Directive ! 238 DI Hiérarchique  Le système d’injection de dépendance d’Angular est hiérarchique  Il possède deux hiérarchie d’injecteur  Une hiérarchie d’injecteur niveau composant (element Injector Hierarchy)  Une hiérarchie d’injecteur niveau module.  La hiérarchie composant (appelé aussi Node Injector Hierarchy) est la plus prioritaire 239 DI Hiérarchique Hiérarchie d’injecteur niveau composant Le système d’injection de dépendance d’Angular est hiérarchique. Un arbre d’injecteur est crée. Cet arbre est // à l’arbre de composant. L’algorithme suivant permet la détection de l’injecteur adéquat : Il l’injecte ok Injection d’un Vérification de service dans un l’injecteur à ce Tant que il ne le composant niveau Vérifie dans le trouve pas et qu’on est père pas arrivé dans la racine 240 DI Hiérarchique Hiérarchie d’injecteur niveau Module  Si Angular ne trouve pas de provider au niveau de la hiérarchie des composants, il va aller voir dans la hiérarchie de module.  Le ModuleInjector peut être configuré de deux manières en utilisant : La propriété @Injectable pour référencer un NgModule, ou ‘root’  Le tableau des providers dans @NgModule()  Le moduleInjector identifie les providers disponibles en effectuant un aplatissement de tous les tableaux de fournisseurs qui peuvent être atteints en suivant les NgModule.imports de manière récursive. 241 242 Exercice Ajouter les services suivants afin d’améliorer la gestion de notre plateforme d’embauche. Un premier service CvService qui gérera les Cvs. Pour le moment c’est lui qui contiendra la liste des cvs que nous avons. Ajouter aussi un composant pour afficher la liste des cvs embauchées ainsi qu’un service EmbaucheService qui gérer les embauches. Au click sur le bouton embaucher d’un Cv, le cv est ajouté à la liste des personnes embauchées et une liste des embauchées apparait. 243 Exercice 244 Exercice 245 DI Hiérarchique Configurer le Mechanism de DI en utilisant les Resolution Modifier  Le mécanisme de DI d’Angular est configurable  Il existe un ensemble de décorateurs qui vous permettent d’adapter le comportement par défaut.  @Optional  @SkipSelf  @Self  @Host 246 DI Hiérarchique Configurer le Mechanism de DI en utilisant les Résolution Modifier : @Optional  @Optional indique qu'une dépendance peut être absente.  Ceci va dire à Angular de retourner null s’il ne trouve pas la dépendance au lieu de déclencher une erreur.  Ceci est utile lorsque vous voulez permettre à un composant de fonctionner même si une dépendance spécifique n'est pas disponible.  Afin de prévenir ca, ajouter le décorateur @Optional devant l’injection.  Cependant, il faut gérer le cas ou l’injection ne se fait pas. 247 DI Hiérarchique Configurer le Mechanism de DI en utilisant les Résolution Modifier : @Optional constructor( @Optional()private logger: LoggerService ){ if (this.logger) { this.logger.log('logged From logger service :D'); } else { console.log('Logged from the external console log') } } 248 DI Hiérarchique Configurer le Mechanism de DI en utilisant les Résolution Modifier : @Self  Si vous voulez considérer uniquement que le provider qui est fourni au niveau du composant et pas dans la hiérarchie de DI, vous pouvez utiliser le décorateur @Self. constructor( @Optional() @Self() private logger: LoggerService ){ if (this.logger) { this.logger.log('logged From logger service :D'); } else { console.log( `No provider in my Providers array, So I’am Logged from the external console log` ) } } 249 DI Hiérarchique Configurer le Mechanism de DI en utilisant les Résolution Modifier : @SkipSelf  Par défaut la hiérarchie de DI commence par chercher un provider au niveau du Composant lui-même.  Imaginez que vous voulez provider un service pour vos fils, mais que vous voulez récupérer une instance dans la hiérarchie qui commence par le composant parent.  Le décorateur @SkipSelf vous permet de le faire. 250 DI Hiérarchique Configurer le Mechanism de DI en utilisant les Résolution Modifier : @Host  Le décorateur @Host arrête la recherche au niveau du composant hôte. Ce qui ressemble à @Self mais avec certaines spécificités.  Le composant hôte est généralement le composant demandant la dépendance.  Cependant, lorsque ce composant est projeté ( avec ng-content ) dans un composant parent, ce composant parent devient l'hôte et il est utilisé en second lieu, donc si l’instance ne se trouve pas dans le composant lui- même on cherche dans le composant dans lequel il est projeté.  Si vous faite une injection dans une directive, le composant appelant la directive devient l’hôte. Cependant il faut utiliser la clé viewProviders 251 Les services Angular  Angular vous fournit certains service prêt à l’empoi et vous permettant certaines fonctionnalités.  Le Core Angular vous fournit 2 services très utiles :  Title  Meta 252 Les services Angular Title  Le service Title vous permet de manipuler la balise title de la page active.  Angular étant une SPA, vous ne pouvez pas modifier directement la balise title dans votre ‘page’  Pour se faire injecter le service Title dans votre page component  Ce service vous offre deux méthode :  setTitle pour modifier le titre  getTitle pour récupérer le titre 253 this.meta.addTag({ Les services Angular name: 'author', content: 'aymen' Meta });  Le service Meta vous permet de man

Use Quizgecko on...
Browser
Browser