• 10 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 12/11/2024

Ajoutez des propriétés personnalisées

Jusqu'ici, vous n'avez aucun moyen de faire afficher d'autres FaceSnaps à votre component car toutes ses données sont codées en dur. C'est dommage : l'un des avantages majeurs d'un component est qu'il est réutilisable, après tout.

Créez une classe FaceSnap

Angular vous permet d'ajouter des propriétés personnalisées à vos components de manière à ce que vous puissiez les injecter depuis le component parent. Ce que ça vous permettrait de faire avec  FaceSnapComponent, ce serait de faire en sorte que  AppComponent  centralise les données de plusieurs FaceSnaps, génère une instance du component pour chaque FaceSnap, et injecte ce FaceSnap à cette instance.

Mais avant de voir comment créer ce type de propriété, profitons de ce moment pour créer votre premier type personnalisé sous forme de classe. On n'a pas envie de devoir injecter un titre, une description, une URL, etc., manuellement à chaque component ! Ce qui serait plus utile, ce serait un modèle de données  FaceSnap, qui comporterait toutes ces propriétés, et que vous pourriez injecter directement dans  FaceSnapComponent, et même utiliser partout dans votre application. Heureusement, TypeScript vous permet de faire exactement ça !

Dans votre dossier  app, créez un sous-dossier  models, et dedans, créez un fichier  face-snap.ts dans lequel vous allez créer une classe FaceSnap. Cette classe comportera toutes les propriétés nécessaires d'un FaceSnap. Ça pourrait être intéressant également d'implémenter un constructor qui faciliterait la création d'objets FaceSnap.

Je vous propose d'essayer d'implémenter cette classe vous-même. Vous trouverez ma proposition ci-dessous :

export class FaceSnap {
  title: string;
  description: string;
  createdDate: Date;
  snaps: number;
  imageUrl: string;
  
  constructor(title: string, description: string, imageUrl: string, createdDate: Date, snaps: number) {
    this.title = title;
    this.description = description;
    this.imageUrl = imageUrl;
    this.createdDate = createdDate;
    this.snaps = snaps;
  }
}

Cette classe comporte tout ce qu'il faut, et nous permet de générer des objets FaceSnap avec la syntaxe  new FaceSnap().

Je voudrais en profiter pour vous montrer un raccourci TypeScript. Si vous avez des propriétés qui seront initialisées par les arguments passés au constructor comme ci-dessus, vous pouvez retirer leurs déclarations et initialisations, et leur ajouter simplement le modificateur  public  dans le  constructor  :

export class FaceSnap {
  constructor(public title: string,
              public description: string,
              public imageUrl: string,
              public createdAt: Date,
              public snaps: number) {}
}

Ces deux déclarations de classe sont identiques en TypeScript, la deuxième permettant un code moins verbeux sans trop de perte de lisibilité.

Maintenant que votre type personnalisé est prêt, faisons en sorte que  FaceSnapComponent  puisse en accepter depuis son parent !

Ajoutez des propriétés personnalisées

Pour qu'une propriété puisse être injectée depuis l'extérieur d'un component, il faut lui ajouter le décorateur  @Input(). Créez maintenant une propriété  faceSnap  de type  FaceSnap  (votre nouveau type !) et mettez-lui ce décorateur :

@Input() faceSnap!: FaceSnap;

Maintenant, dans  app.component.ts  – le parent de FaceSnapComponent – créez une propriété de type  FaceSnap  et initialisez-la dans  ngOnInit().

import { Component, OnInit } from '@angular/core';
import { FaceSnapComponent } from './face-snap/face-snap.component';
import { FaceSnap } from './models/face-snap';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [
    FaceSnapComponent
  ],
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss'
})
export class AppComponent implements OnInit {
  mySnap!: FaceSnap;

  ngOnInit() {
    this.mySnap = new FaceSnap(
      'Archibald',
      'Mon meilleur ami depuis tout petit !',
      'https://cdn.pixabay.com/photo/2015/05/31/16/03/teddy-bear-792273_1280.jpg',
      new Date(),
      0
    );
  }
}

Vous allez maintenant utiliser l'attribut binding pour lier cet objet à la propriété personnalisée  faceSnap  de FaceSnapComponent dans  app.component.html  :

<app-face-snap [faceSnap]="mySnap"></app-face-snap>

Il reste néanmoins une dernière étape.  FaceSnapComponent  affiche toujours ses propriétés codées en dur. Il faut donc modifier son template pour utiliser les données de la nouvelle propriété  faceSnap  :

<div class="face-snap-card">
  <h2>{{ faceSnap.title }}</h2>
  <img [src]="faceSnap.imageUrl" [alt]="faceSnap.title">
  <p>{{ faceSnap.description }}</p>
  <p>FaceSnap créée le {{ faceSnap.createdAt }}</p>
  <p>
    <button (click)="onSnap()">{{ snapButtonText }}</button>
    🤌 {{ faceSnap.snaps }}
  </p>
</div>

Vous pouvez donc supprimer les propriétés  title,  description,  imageUrl,  createdDate  et  snaps  de FaceSnapComponent.

Mais ça crée une erreur de compilation ! Comment la corriger ?

Cette erreur est plutôt simple à corriger : la suppression de  snaps  fait que votre méthode  onSnap()  n'est plus correcte. Voici la solution, très simple.

Dans  face-snap.ts  , ajoutez des méthodes d'instance pour gérer l'ajout et le retrait d'un snap :

export class FaceSnap {
  constructor(public title: string,
              public description: string,
              public imageUrl: string,
              public createdAt: Date,
              public snaps: number) {}

  addSnap(): void {
    this.snaps++;
  }

  removeSnap(): void {
    this.snaps--;
  }
}

Et appelez ces méthodes dans  face-snap.component.ts  !

unSnap() {
    this.faceSnap.removeSnap();
    this.snapButtonText = 'Oh Snap!';
    this.userHasSnapped = false;
  }

snap() {
    this.faceSnap.addSnap();
    this.snapButtonText = 'Oops, unSnap!';
    this.userHasSnapped = true;
}

Comme vous pouvez le remarquer, la nouvelle propriété  faceSnap  est utilisée comme toute autre propriété.

Enfin, pour vérifier que tout fonctionne correctement, et comme dernier challenge, ajoutez deux autres instances de  FaceSnapComponent  en injectant deux autres objets FaceSnap que vous aurez préalablement créés. Vous pouvez voir mon résultat à moi à la fin de la vidéo ci-dessus !

En résumé

  • N'hésitez pas à créer vos propres types, sous forme de classe par exemple, pour faciliter la manipulation de données dans votre application.

  • Une propriété personnalisée est rendue injectable depuis l'extérieur grâce au décorateur  @Input()

  • Une propriété en  @Input()  est utilisable comme n'importe quelle autre propriété : on peut en afficher les éléments, les modifier… 

  • On lie ensuite une valeur à cette propriété depuis le component parent avec l'attributattribut, c'est-à-dire le nom de la propriété entre crochets  []  en passant la valeur entre les guillemets ; ex. : [faceSnap]="mySnap"

Qu'avez-vous appris dans cette partie du cours ?

  • Vous avez créé votre premier component.

  • Vous avez utilisé la strinleinterpolation pour afficher des valeurs dans le template.

  • Vous avez employé l'attributattribut, d'abord pour lier des valeurs à des attributs natifs HTML comme la src d'une image, et ensuite à une propriété personnalisée de votre component.

  • Vous avez réagi à des événements venant du template avec l'event binding.

Dans la prochaine partie du cours, vous allez découvrir un nouvel outil Angular pour gérer dynamiquement la structure de vos components : les Directives. Avant de les découvrir, je vous invite à faire le quiz suivant pour valider vos acquis !

Exemple de certificat de réussite
Exemple de certificat de réussite