Avez-vous une question? (216) 97 656 803 hajjriadh@gmail.com
Angular

Introduction au component Angular

Toute l’interface d’une application Angular est faite de composants. Découvrez leur structure (classe, template, styles), le rôle du décorateur @Component, les trois formes de sélecteur et l’encapsula...

0 chapitres 0 QCM Accès gratuit
Dans cet article

À propos de ce cours

Toute l’interface d’une application Angular est faite de composants. Découvrez leur structure (classe, template, styles), le rôle du décorateur @Component, les trois formes de sélecteur et l’encapsulation des styles, à travers un exemple complet et sept activités.
  1. Objectifs

    • Comprendre ce qu'est un composant (component) Angular et pourquoi toute l'interface d'une application en est faite
    • Lire une page comme un arbre de composants: composant racine, parents et enfants
    • Connaître les fichiers d'un composant et le rôle de chacun : classe, template, styles, test
    • Expliquer les métadonnées du décorateur @Component: selector, templateUrl / template, styleUrl / styles, imports
    • Utiliser les trois formes de sélecteur: élément, attribut et classe
    • Afficher un composant dans un autre et comprendre que chaque balise crée une instance indépendante
    • Comprendre l'encapsulation des styles et le cycle de vie de base (constructor, ngOnInit)
    • Reconnaître et corriger les erreurs les plus fréquentes (NG8001, NG2008, NG8023…)
  2. Présentation

    • Angular est un framework, écrit en TypeScript, qui sert à construire des applications web d'une seule page (SPA). Il est livré sous forme de bibliothèques (@angular/core, @angular/router, @angular/forms…) que l'on importe dans son application.
    • Dans une application Angular, tout ce que l'utilisateur voit est produit par des composants. Un composant est un morceau d'interface autonome: il possède sa vue (HTML), son apparence (CSS) et son comportement (TypeScript).
    • C'est vous qui décidez de la taille d'un composant : il peut représenter un simple bouton, une carte, un formulaire ou un écran entier. Plus un composant est petit et spécialisé, plus il est facile à comprendre, à tester et à réutiliser.
    • On peut comparer les composants à des briques de construction : on assemble de petites briques (une carte de formation, un badge) pour en former de plus grandes (une liste, une page), jusqu'à l'application complète.

Une page Angular découpée en composants : en-tête, badge, cartes de formation et pied de page

  1. Définition

Un composant est une classe TypeScript décorée avec @Component, associée à un template HTML qui définit sa vue et, facultativement, à des styles CSS. Angular l'affiche partout où l'on écrit son sélecteur dans un template.
  • Un composant réunit donc trois éléments :
    • une classe: les données (propriétés) et le comportement (méthodes) ;
    • un template: le HTML affiché, enrichi par la syntaxe d'Angular ({{ }}, (click), @if…) qui le relie à la classe : c'est le data binding;
    • des métadonnées, fournies par le décorateur @Component, qui indiquent à Angular que la classe est un composant, comment l'insérer dans une page et quels fichiers l'accompagnent.
  • Un peu d'histoire : dans la documentation officielle, un composant est une directive avec un template. Les directives sans template (qui modifient le comportement d'une balise existante) sont étudiées plus loin dans le cours.
  • L'arbre des composants

    • Une application part toujours d'un composant racine (root component). Dans un projet créé avec ng new, il s'appelle App, son sélecteur est app-root, et il est démarré par src/main.ts:
    // src/main.ts
    import { bootstrapApplication } from '@angular/platform-browser';
    import { appConfig } from './app/app.config';
    import { App } from './app/app';
    
    bootstrapApplication(App, appConfig)
      .catch((err) => console.error(err));
    <!-- src/index.html (extrait) -->
    <body>
      <app-root></app-root>
    </body>
    • bootstrapApplication(App) cherche la balise <app-root> dans index.html et la remplace par le composant App.
    • Le template de App contient à son tour les sélecteurs d'autres composants (l'en-tête, les cartes, le pied de page), qui peuvent eux-mêmes en contenir d'autres. Cette imbrication forme l'arbre des composants.
    • Un composant qui en affiche un autre est son parent; le composant affiché est son enfant. Cette relation sera essentielle dans la leçon Communication entre composants : le parent transmet des données à ses enfants, les enfants préviennent leur parent.

    Arbre des composants Angular : App, Entete, Badge, CarteFormation et PiedPage

    1. Préparer un projet de découverte

    ng new decouverte-composants --style=css --ssr=false
    cd decouverte-composants
    code .
    • Ouvrir src/app/app.ts. C'est déjà un composant :
    import { Component, signal } from '@angular/core';
    import { RouterOutlet } from '@angular/router';
    
    @Component({
      imports: [RouterOutlet],
      selector: 'app-root',
      styleUrl: './app.css',
      templateUrl: './app.html',
    })
    export class App {
      protected readonly title = signal('decouverte-composants');
    }
    • Deux mots nouveaux dans ce code : signal() crée une valeur « réactive » qu'Angular surveille (les signaux sont étudiés plus loin) ; protected indique que la propriété est réservée au composant et à son template, comme le recommande le guide de style d'Angular. Dans cette leçon, on utilise des propriétés simples pour se concentrer sur la structure du composant.
    • Vider le fichier app.html (il contient la page d'accueil de démonstration d'Angular) et retirer RouterOutlet de app.ts: on va construire notre propre page.
  • Générer un composant avec Angular CLI

    • On ne crée pas les fichiers d'un composant à la main : la commande ng generate component (abrégée ng g c) les crée avec le bon contenu et les bons noms.
    ng generate component carte-formation
    ng g c entete --inline-template --inline-style
    ng g c pied-page
    ng g c badge

    Terminal : génération de composants Angular avec ng generate component

    • Les options les plus utiles :
    Option Effet
    --inline-template (-t) le HTML est écrit dans le fichier .ts (propriété template), pas de fichier .html
    --inline-style (-s) le CSS est écrit dans le fichier .ts (propriété styles), pas de fichier .css
    --skip-tests pas de fichier .spec.ts
    --flat pas de dossier propre au composant : les fichiers sont créés directement dans le dossier courant
    --dry-run affiche les fichiers qui seraient créés, sans rien écrire : pratique pour vérifier un chemin
    ng g c formations/liste-formations crée le composant dans le sous-dossier src/app/formations/
    • Conventions de nommage : le nom passé à la CLI est écrit en kebab-case (carte-formation). La CLI en déduit le nom des fichiers (carte-formation.ts), le nom de la classe en PascalCase (CarteFormation) et le sélecteur avec le préfixe du projet (app-carte-formation).
  • Anatomie d'un composant

    • La commande ng g c carte-formation a créé un dossier contenant quatre fichiers :
    Fichier Rôle Contenu généré
    carte-formation.ts la classe et ses métadonnées @Component la classe vide CarteFormation
    carte-formation.html le template: la vue du composant <p>carte-formation works!</p>
    carte-formation.css les styles propres au composant vide
    carte-formation.spec.ts le test unitaire, lancé par ng test un test qui vérifie que le composant se crée
    • Voici le fichier carte-formation.ts tel que la CLI le génère :
    import { Component } from '@angular/core';
    
    @Component({
      imports: [],
      selector: 'app-carte-formation',
      styleUrl: './carte-formation.css',
      templateUrl: './carte-formation.html',
    })
    export class CarteFormation {}
    • On le complète avec des propriétés (les données de la carte) et une méthode (réserver une place). Un accesseur get complet calcule si la session est pleine :
    // carte-formation.ts
    import { Component } from '@angular/core';
    
    @Component({
      imports: [],
      selector: 'app-carte-formation',
      styleUrl: './carte-formation.css',
      templateUrl: './carte-formation.html',
    })
    export class CarteFormation {
      titre = 'Développement Angular';
      dureeHeures = 120;
      prix = 1200;
      places = 3;
    
      get complet(): boolean {
        return this.places === 0;
      }
    
      reserver(): void {
        if (this.places > 0) {
          this.places--;
        }
      }
    }
    <!-- carte-formation.html -->
    <article class="carte">
      <h3>{{ titre }}</h3>
      <p>{{ dureeHeures }} heures – {{ prix }} DT</p>
      <p class="places">
        @if (complet) {
          Session complète
        } @else {
          Places restantes : {{ places }}
        }
      </p>
      <button type="button" (click)="reserver()" [disabled]="complet">
        Réserver
      </button>
    </article>
    /* carte-formation.css */
    .carte {
      border: 1px solid #cbd5e1;
      border-radius: 10px;
      padding: 16px;
      width: 240px;
      background: #fff;
    }
    h3 { color: #dd0031; margin: 0 0 8px; }
    .places { font-weight: bold; }
    button {
      background: #dd0031; color: #fff; border: none;
      border-radius: 6px; padding: 6px 14px; cursor: pointer;
    }
    button:disabled { background: #94a3b8; cursor: not-allowed; }
    • Dans le template, la classe et la vue sont reliées par le data binding:
      • {{ titre }} (interpolation) affiche la valeur d'une propriété de la classe ;
      • (click)="reserver()" (liaison d'événement) appelle une méthode de la classe quand on clique ;
      • [disabled]="complet" (liaison de propriété) donne à une propriété HTML la valeur d'une expression ;
      • @if / @else affiche un bloc ou un autre selon une condition.
    • Le template ne peut utiliser que ce que la classe possède : une faute de frappe comme {{ titr }} est détectée à la compilation (TS2551: Property 'titr' does not exist on type 'CarteFormation'. Did you mean 'titre'?). Chaque syntaxe est détaillée dans les leçons sur le data binding.

    Anatomie d'un composant Angular : fichier TypeScript, template HTML, styles CSS et test

    1. Le décorateur @Component et ses métadonnées

      • @Component est un décorateur (voir Présentation des décorateurs) : une fonction placée juste avant la classe, qui reçoit un objet de configuration. Sans lui, CarteFormation ne serait qu'une classe TypeScript ordinaire.
      • Les propriétés de cet objet s'appellent les métadonnées du composant :
    Métadonnée Rôle Exemple
    selector le sélecteur CSS qui indique où insérer le composant dans un template 'app-carte-formation'
    templateUrl chemin du fichier HTML du template './carte-formation.html'
    template le template écrit directement dans le fichier .ts (à la place de templateUrl) `<h1>{{ nomCentre }}</h1>`
    styleUrl chemin d'un fichier CSS './carte-formation.css'
    styleUrls tableau de plusieurs fichiers CSS (ancienne écriture, toujours valable) ['./carte.css', './theme.css']
    styles le CSS écrit directement dans le fichier .ts `h1 { margin: 0; }`
    imports les composants, directives et pipes utilisés dans le template [Entete, CarteFormation]
    • Ce qui est obligatoire : un composant doit avoir un template, avec template ou templateUrl (jamais les deux). Les styles sont facultatifs. Le sélecteur est presque toujours présent ; il n'est inutile que pour un composant affiché uniquement par le routeur (une page), ce que l'on verra avec le routage.
  • template ou templateUrl ?

    • Le composant Entete a été généré avec --inline-template --inline-style: tout tient dans un seul fichier. Les accents graves (backticks) permettent d'écrire le HTML et le CSS sur plusieurs lignes :
    // src/app/entete/entete.ts
    import { Component } from '@angular/core';
    
    @Component({
      imports: [],
      selector: 'app-entete',
      styles: `
        header { background: #1e293b; color: #fff; padding: 16px 24px; }
        h1 { margin: 0; font-size: 1.6rem; }
        p { margin: 4px 0 0; color: #94a3b8; }
      `,
      template: `
        <header>
          <h1>{{ nomCentre }}</h1>
          <p>{{ slogan }}</p>
        </header>
      `,
    })
    export class Entete {
      nomCentre = 'FormaPlus';
      slogan = 'Centre de formation professionnelle';
    }
    • Règle pratique : un template de quelques lignes peut rester dans le fichier .ts; dès qu'il grandit, on utilise un fichier séparé, plus lisible et mieux pris en charge par l'éditeur (coloration, autocomplétion HTML). C'est le choix par défaut de la CLI.
    1. Le sélecteur : où afficher le composant

      • Le sélecteur s'écrit comme un sélecteur CSS. Angular accepte trois formes :
    // 1. Élément (balise)
    @Component({
      selector: 'app-entete',
      …
    })
    export class Entete {}
    
    // Utilisation
    // <app-entete />
    // 2. Attribut
    @Component({
      selector: '[app-pied-page]',
      …
    })
    export class PiedPage {}
    
    // Utilisation
    // <footer app-pied-page></footer>
    // 3. Classe CSS
    @Component({
      selector: '.app-badge',
      …
    })
    export class Badge {}
    
    // Utilisation
    // <span class="app-badge"></span>

    Les trois formes du sélecteur d'un composant Angular : élément, attribut et classe

    • L'élément est la forme normale, celle que génère la CLI. Le préfixe (app- par défaut, réglable dans angular.json avec "prefix") évite les conflits avec les balises HTML et avec les composants des bibliothèques.
    • L'attribut est utile quand la balise doit rester une vraie balise HTML : un <footer> pour l'accessibilité, une ligne <tr> dans un tableau (un tableau n'accepte pas de balise inconnue entre <tbody> et <tr>).
    • La classe est rare pour un composant ; on la rencontre surtout dans du code ancien.
    • Balise auto-fermante : depuis Angular 15.1, on peut écrire <app-entete /> au lieu de <app-entete></app-entete>, quand le composant n'a pas de contenu entre ses balises.
  • Afficher un composant dans un autre

    • Pour qu'un parent affiche un enfant, il faut deux choses:
      1. importer la classe de l'enfant et l'ajouter au tableau imports du décorateur du parent ;
      2. écrire le sélecteur de l'enfant dans le template du parent.
    // src/app/app.ts
    import { Component } from '@angular/core';
    import { Entete } from './entete/entete';
    import { CarteFormation } from './carte-formation/carte-formation';
    import { PiedPage } from './pied-page/pied-page';
    import { Badge } from './badge/badge';
    
    @Component({
      imports: [Entete, CarteFormation, PiedPage, Badge],
      selector: 'app-root',
      styleUrl: './app.css',
      templateUrl: './app.html',
    })
    export class App {}
    <!-- src/app/app.html -->
    <app-entete />
    
    <main>
      <h3>Nos formations <span class="app-badge"></span></h3>
      <div class="cartes">
        <app-carte-formation />
        <app-carte-formation />
      </div>
    </main>
    
    <footer app-pied-page></footer>
    /* src/app/app.css */
    main { padding: 16px 24px; }
    .cartes { display: flex; gap: 16px; }
    // src/app/pied-page/pied-page.ts
    import { Component } from '@angular/core';
    
    @Component({
      imports: [],
      selector: '[app-pied-page]',
      styleUrl: './pied-page.css',
      templateUrl: './pied-page.html',
    })
    export class PiedPage {
      annee = new Date().getFullYear();
    }
    <!-- pied-page.html -->
    <p>© {{ annee }} FormaPlus – Tous droits réservés</p>
    // src/app/badge/badge.ts
    import { Component } from '@angular/core';
    
    @Component({
      imports: [],
      selector: '.app-badge',
      styleUrl: './badge.css',
      templateUrl: './badge.html',
    })
    export class Badge {
      texte = 'Nouveau';
    }
    /* badge.css : :host désigne la balise du composant lui-même */
    :host {
      background: #16a34a; color: #fff;
      border-radius: 999px; padding: 2px 10px; font-size: 0.8rem;
    }
    • Lancer ng serve et ouvrir http://localhost:4200. Cliquer trois fois sur le bouton de la première carte, puis une fois sur celui de la seconde :

    Résultat dans le navigateur : deux instances indépendantes du composant CarteFormation

    • Une balise = une instance. Chaque <app-carte-formation /> crée un nouvel objet de la classe CarteFormation, avec ses propres propriétés : réserver dans la première carte ne change rien à la seconde.
    • Les deux cartes affichent pour l'instant la même formation, car le titre est écrit dans la classe. Dans la leçon Communication entre composants, le parent transmettra à chaque carte sa formation avec input().
    • Si l'import est oublié, la compilation échoue avec l'erreur NG8001. Angular indique le fichier, la ligne et la solution : ajouter le composant au tableau imports.

    Erreur Angular NG8001 : app-carte-formation is not a known element

    • L'inverse produit un avertissement : un composant présent dans imports mais absent du template donne NG8113: Badge is not used within the template of App. Ce n'est pas bloquant, mais il faut retirer l'import inutile.
  • L'encapsulation des styles

    • Le fichier carte-formation.css colore les titres h3 en rouge. Pourtant, le titre « Nos formations », qui est aussi un h3 mais appartient au template de App, reste noir.
    • Angular isole les styles de chaque composant : il ajoute un attribut unique (_ngcontent-…) à toutes les balises du template du composant et réécrit chaque règle CSS du composant avec cet attribut. Ouvrir les outils de développement du navigateur (F12, onglet Éléments) pour le constater :

    Encapsulation des styles Angular : attributs _ngcontent et _nghost dans le DOM

    • Conséquences pratiques :
      • on peut écrire des sélecteurs simples (h3, button, .carte) dans un composant sans risque de modifier le reste de l'application ;
      • la balise du composant elle-même (<app-carte-formation>) se stylise avec le sélecteur spécial :host (voir badge.css) ;
      • les styles communs à toute l'application (police, couleur de fond, Bootstrap) vont dans src/styles.css ou dans angular.json, comme dans le TP 1.
  • Le cycle de vie en bref

    • Angular crée, met à jour et détruit les composants. À certaines étapes, il appelle des méthodes de la classe, appelées hooks du cycle de vie. Les deux premières à connaître :
    import { Component, OnInit } from '@angular/core';
    
    @Component({ … })
    export class CarteFormation implements OnInit {
      constructor() {
        console.log('1. constructor : la classe est créée');
      }
    
      ngOnInit(): void {
        console.log('2. ngOnInit : le composant est prêt');
      }
    }
    # Console du navigateur (2 cartes)
    1. constructor : la classe est créée
    1. constructor : la classe est créée
    2. ngOnInit : le composant est prêt
    2. ngOnInit : le composant est prêt
    Méthode Appelée… Usage
    constructor() à la création de l'objet initialiser des propriétés simples, récupérer des services avec inject()
    ngOnInit() une fois, quand Angular a préparé le composant et ses données d'entrée charger des données, démarrer un traitement
    ngOnDestroy() juste avant la suppression du composant arrêter un minuteur, se désabonner
    • Pourquoi implements OnInit? L'interface OnInit oblige la classe à écrire correctement ngOnInit(): une faute de frappe (ngOninit) serait signalée par le compilateur au lieu d'être ignorée en silence (voir Les interfaces de classe en TypeScript).
  • Anciennes et nouvelles écritures

    • Angular a beaucoup évolué. Les tutoriels et les projets anciens que vous rencontrerez utilisent souvent une autre écriture. Voici comment les reconnaître :
    Élément Ancienne écriture Écriture actuelle
    Noms de fichier et de classe app.component.ts, AppComponent app.ts, App (depuis Angular 20)
    Déclaration des composants tableau declarations d'un NgModule (app.module.ts) composants autonomes (standalone, par défaut depuis Angular 19) et tableau imports de chaque composant
    Un fichier de styles styleUrls: ['./app.component.css'] styleUrl: './app.css'
    Conditions dans le template <p *ngIf="complet"> @if (complet) { … }
    Balise vide <app-entete></app-entete> <app-entete />
    • Le composant suivant, écrit pour une ancienne version d'Angular, fonctionne toujours, à condition que le fichier app.component.css existe :
    import { Component } from '@angular/core';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      title = 'exemple';
    }
    1. Bonnes pratiques

      • Un composant, une responsabilité : une carte affiche une formation, une liste affiche des cartes. Si un template dépasse une centaine de lignes, c'est souvent le signe qu'il faut le découper.
      • Toujours générer avec la CLI (ng g c) : les noms, le préfixe et le test sont cohérents.
      • Ranger par fonctionnalité : layout/entete, layout/pied-page, formations/liste-formations, formations/carte-formation, comme dans le TP 1.
      • Garder la logique dans la classe et un template simple : pas de calcul compliqué dans {{ }}, mais une méthode ou un accesseur (get complet).
      • Lire les messages du compilateur : les erreurs Angular indiquent le fichier, la ligne, et souvent la solution.
    2. Activité 1 : générer et afficher un composant

      • Dans le projet decouverte-composants, reproduire les composants de la leçon : Entete, CarteFormation, PiedPage et Badge, puis les afficher dans App.
      • Générer un composant presentation qui affiche un paragraphe de présentation du centre, avec une propriété anneeCreation = 2010 et l'âge du centre calculé par un accesseur get anciennete(). L'afficher entre l'en-tête et la liste des cartes.
      • Vérifier avec ng build qu'il n'y a ni erreur ni avertissement.
    3. Activité 2 : les trois formes du sélecteur

      • Changer le sélecteur de Badge en attribut ([app-badge]) et adapter app.html. Le badge s'affiche-t-il toujours ?
      • Donner à PiedPage le sélecteur app-entete, puis compiler. Noter le message obtenu (NG8023) et expliquer pourquoi Angular refuse. Revenir au sélecteur d'origine.
      • Expliquer en une phrase pourquoi on choisit le sélecteur d'attribut pour un composant qui représente une ligne <tr> d'un tableau.
    4. Activité 3 : template et styles en ligne ou séparés

      • Transformer Entete pour qu'il utilise des fichiers séparés : créer entete.html et entete.css, y déplacer le HTML et le CSS, et remplacer template et styles par templateUrl et styleUrl.
      • Faire l'inverse pour Badge: template et styles en ligne, puis supprimer ses fichiers .html et .css.
      • Mettre volontairement un mauvais nom de fichier dans un templateUrl et noter le message (NG2008: Could not find template file …).
    5. Activité 4 : propriétés et méthodes

      • Dans CarteFormation, ajouter une constante capacite = 3, une méthode annuler() qui rend une place (sans dépasser la capacité) et un deuxième bouton « Annuler », désactivé quand aucune place n'a été réservée.
      • Afficher le taux de remplissage avec un accesseur get tauxRemplissage() (par exemple « 67 % »), arrondi avec Math.round.
      • Vérifier que les deux cartes restent indépendantes.
    6. Activité 5 : observer l'encapsulation

      • Ouvrir les outils de développement (F12) et relever les attributs _nghost-… et _ngcontent-… d'une carte et de l'en-tête. Les deux cartes ont-elles le même attribut ? Pourquoi ?
      • Ajouter h3 { text-decoration: underline; } dans src/styles.css. Quels titres sont soulignés ? Expliquer la différence avec la règle h3 de carte-formation.css.
      • Dans carte-formation.css, ajouter une règle :host { display: block; } et observer dans les outils de développement sur quelle balise elle s'applique.
    7. Activité 6 : lire les erreurs

      • Provoquer une à une les erreurs suivantes, noter le message en commentaire dans votre code, puis corriger :
        • retirer CarteFormation du tableau imports de App (NG8001) ;
        • écrire {{ titr }} dans le template de la carte (TS2551) ;
        • écrire (click)="reserver" sans parenthèses (avertissement NG8111) ;
        • écrire @if (complet()) alors que complet est un accesseur (TS6234) ;
        • supprimer le décorateur @Component de Badge (NG2012).
    8. Activité 7 : retour sur le projet FormaPlus

      • Dans votre projet forma-plus du TP 1, dessiner l'arbre des composants de la page d'accueil (sur papier ou dans le README.md) : composant racine, parents, enfants, avec leur sélecteur.
      • Générer un composant accueil/temoignages qui affiche deux avis de stagiaires dans des cartes Bootstrap, et l'insérer avant le formulaire de contact.
      • Faire un commit dans chaque dépôt : git commit -m "Composants : activité N", puis un push.
    9. Erreurs fréquentes

    Message Cause Solution
    NG8001: 'app-x' is not a known element Composant utilisé dans un template sans être importé, ou faute de frappe dans le sélecteur Ajouter la classe au tableau imports du parent ; vérifier le sélecteur
    NG8113: X is not used within the template of Y Composant importé mais jamais utilisé Retirer l'import, ou utiliser le composant
    NG2008: Could not find template file './x.html'. Chemin de templateUrl incorrect Corriger le nom ou le chemin (relatif au fichier .ts)
    NG8023: Multiple components match node with tagname … Deux composants importés ont le même sélecteur Donner un sélecteur unique à chaque composant
    NG2012: Component imports must be standalone components, directives, pipes, or must be NgModules. Une classe sans décorateur @Component placée dans imports Ajouter le décorateur, ou importer la bonne classe
    TS2551: Property 'x' does not exist on type 'Y'. Did you mean …? Le template utilise une propriété inexistante (faute de frappe) Corriger le nom, ou ajouter la propriété à la classe
    NG8111: Function in event binding should be invoked (click)="reserver": la méthode n'est pas appelée Écrire (click)="reserver()"
    1. À retenir

      • Un composant = une classe + un template + des styles facultatifs, réunis par le décorateur @Component.
      • L'application forme un arbre de composants qui part du composant racine App (app-root), démarré par bootstrapApplication.
      • On génère un composant avec ng g c nom: fichiers .ts, .html, .css et .spec.ts.
      • Métadonnées principales : selector, templateUrl ou template, styleUrl ou styles, imports.
      • Pour afficher un enfant : l'ajouter aux imports du parent et écrire son sélecteur dans le template. Chaque balise crée une instance indépendante.
      • Les styles d'un composant sont encapsulés: ils ne s'appliquent qu'à son template.
      • ngOnInit() est appelée une fois, quand le composant est prêt.
    Penser Angular, c'est penser en composants : avant d'écrire une ligne de code, découpez l'écran en morceaux, nommez-les, et dessinez leur arbre.