Fermer

mai 13, 2024

Composants dynamiques et flexibles avec projection de contenu angulaire

Composants dynamiques et flexibles avec projection de contenu angulaire


Angular propose la projection de contenu, une option plus flexible que l’utilisation d’entrées et la nécessité de modifier le modèle si nous devons mettre à jour un composant. Nous allons jeter un coup d’oeil!

Lors de la création d’applications, il est important de présenter les données et les informations aux utilisateurs de manière attrayante et cohérente.

Par exemple, imaginez une page de blog avec des cartes dans le style de Netflix. Chaque carte est différente, mais le contenant de la carte reste le même. Le conteneur de cartes est un modèle HTML et nous ne voulons pas répéter le balisage HTML ni avoir besoin de modifier chaque carte lorsque nous souhaitons un changement, car cela est sujet à des erreurs ou pourrait interrompre l’interface utilisateur.

Pour résoudre ce genre de situation, nous utilisons des bibliothèques comme Progress Interface utilisateur Kendo pour angulairedont Carte Le composant est suffisamment flexible pour ajouter et modifier les informations ou pour ajouter du contenu personnalisé. Nous pouvons ajouter des éléments personnalisés comme des images ou du texte à l’intérieur du <kendo-card> composant ou restituer le contenu et d’autres composants dans un endroit spécifique comme <kendo-actions>ce qui nous permet de créer facilement de superbes cartes avec notre contenu personnalisé.

Ces types de composants sont très utiles pour nos applications. Ils aident à accélérer le développement, à simplifier notre base de code, à réutiliser le code et à réduire les erreurs.

Lorsque l’équipe Kendo UI entreprend de créer un composant tel que la carte, elle commence par quelques fonctionnalités angulaires pour le rendre flexible pour de larges cas d’utilisation, tout comme nous le ferions si nous construisions le composant à partir de zéro. Et si je vous disais que nous pouvons apprendre à construire un composant avec la même flexibilité dans un scénario réel avec seulement quelques lignes comme l’équipe Kendo UI ?

Aujourd’hui, nous allons apprendre quelques façons de rendre nos composants flexibles à l’aide des fonctionnalités angulaires, et chaque méthode nous permet d’offrir plus de flexibilité avec moins de lignes de code.

Faisons-le!

Scénario

Disons que nous avons été embauchés pour montrer une liste de Classe virtuelle de progrès cours avec un modèle HTML. Chaque cours comprendra le titre, la vignette, la durée et les notes.

Comment pouvons-nous créer une page pour afficher les cours sans dupliquer le HTML ? Si nous y parvenons, nous obtiendrons un composant très agréable et flexible.

Au fait, la classe virtuelle est un excellent moyen d’en apprendre davantage sur l’interface utilisateur du Kendo !

Configurer le projet

Tout d’abord, nous récupérons le code du dépôt. Dans votre terminal, exécutez la commande suivante pour cloner le projet :

git clone https://github.com/danywalls/angular-content-projection
Cloning into 'angular-content-projection'...
remote: Enumerating objects: 66, done.
remote: Counting objects: 100% (66/66), done.
remote: Compressing objects: 100% (39/39), done.
Receiving objects: 100% (66/66), 123.72 KiB | 1.49 MiB/s, done.
Resolving deltas:   0% (0/21)
Resolving deltas: 100% (21/21), done.

Accédez au angular-content-projection dossier et exécutez le npm install commande dans le terminal pour installer toutes les dépendances requises, afin que nous soyons prêts pour notre prochaine étape.

Une fois cela terminé, allez dans le répertoire et exécutez ng serve -o pour voir votre projet prêt !

Deux cartes montrant les cours d'apprentissage ThemeBuilder d'Angular 17, avec la durée et les étoiles pour chacun.

Si vous ouvrez app.component.html, vous trouverez le modèle HTML en double suivant pour afficher deux cours. Ce n’est pas la meilleure façon. Pourquoi ne pas le déplacer dans un composant comme première approche pour réduire le code en double ?

Créer le composant

Dans le répertoire racine, utilisez Angular CLI pour générer le nouveau composant course-card :

ng g c components/course-card
CREATE src/app/components/course-card/course-card.component.html (27 bytes)
CREATE src/app/components/course-card/course-card.component.spec.ts (648 bytes)
CREATE src/app/components/course-card/course-card.component.ts (265 bytes)
CREATE src/app/components/course-card/course-card.component.css (0 bytes)
> 

Ensuite, copiez le balisage HTML d’un cours à partir de app.component.html à course-card.component.html.

  <div class="course-container">
      <div class="course-thumbnail">
        <img src="../assets/angular.jpeg"/>
        <div class="course-status">
          New
        </div>
      </div>
      <h3 class="title">Angular 17</h3>
      <div class="course-footer">
        <span>🕧 3h 00m</span>
        <span>5 ⭐</span>
      </div>
    </div>

Le HTML d'en haut dans sa maison

Ensuite, importez CourseCardComponent dans le app.component.ts

import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { CourseCardComponent} from "./components/course-card/course-card.component";

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, CourseCardComponent],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css'
})
export class AppComponent {
}

Et utilisez-le dans le app.component.html balisage.

<div>
  <h1>Kendo Learning</h1>
  <div class="container">
    <app-course-card/>
  </div>
</div>

Enregistrez les modifications et notre composant de cours fonctionne avec le balisage HTML ! Notre premier objectif, à savoir encapsuler le code HTML dans notre composant de cours, est atteint !

Page d'apprentissage du Kendo montrant le cours Angular 17

Notre prochain défi est de savoir comment modifier le titre, l’image et d’autres informations pour rendre notre composant de cours flexible aux changements. Nous pouvons utiliser les signaux d’entrée dans Angular. Faisons-le!

Si vous n’avez jamais joué avec Angular Input, je vous recommande fortement de jeter un œil Créez des applications réactives avec Signals, RxJS et Angular 17.

Transmission de données à l’aide d’entrées

Nous devons faire une petite refactorisation du composant du cours pour permettre de modifier le contenu de manière dynamique à l’aide des entrées. Tout d’abord, au-dessus de notre composant app-course-card, déclarez un type course correspondant aux propriétés du cours.

export type Course = {
  title: string;
  image: string;
  rank: number;
  timeSpan: string;
}

Ensuite, déclarez un élément requis input propriété de type Course dans notre nouveau composant de carte. Cela nous permettra d’envoyer un cours dynamique de app.component.ts et modifiez le contenu de manière dynamique plutôt qu’avec des valeurs codées en dur.

export class CourseCardComponent {
  course = input.required<Course>()
}

Le code final dans course.component.ts devrait ressembler à ceci :

import {Component, input} from '@angular/core';

export type Course = {
  title: string;
  image: string;
  rank: number;
  timeSpan: string;
}
@Component({
  selector: 'app-course-card',
  standalone: true,
  imports: [],
  templateUrl: './course-card.component.html',
  styleUrl: './course-card.component.css'
})
export class CourseCardComponent {
  course = input.required<Course>()
}

Enfin, liez les propriétés du cours dans le course.component.html modèle, en utilisant l’interpolation : {{course().title}}. Parce que l’entrée est un signal, nous devons appeler course() et la propriété, par exemple, course().image. Remplacez le texte codé en dur par la propriété d’entrée du cours.

Le code final devrait ressembler à ceci :

<div class="course-container">
  <div class="course-thumbnail">
    <img [src]="course().image"/>
    <div class="course-status">
      New
    </div>
  </div>
  <h3 class="title">{{ course().title }}</h3>
  <div class="course-footer">
    <span>🕧 {{ course().timeSpan }}</span>
    <span>{{course().rank}} ⭐</span>
  </div>
</div>

Parfait, mais comment faire un vrai test pour vérifier si notre composant lie dynamiquement plusieurs cours ? Tout d’abord, ouvrez le app.component.ts fichier et créez un tableau de cours avec des valeurs aléatoires.

import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import {Course, CourseCardComponent} from "./components/course-card/course-card.component";

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, CourseCardComponent],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css'
})
export class AppComponent {
  title = 'play-with-content-projection';
  courses : Array<Course> = [
    {
      title: 'Angular 17 soon 18!',
      image: '../../../assets/angular.jpeg',
      rank: 5,
      timeSpan: "2h"
    },
    {
      title: 'Theme Builder!',
      image: '../../../assets/theme-builder.jpeg',
      rank: 5,
      timeSpan: "2h"
    }
  ]
}

Ensuite, ouvrez le modèle et utilisez @for pour parcourir le tableau courses, en liant la propriété input à chaque cours.

Le code final ressemble à ceci :

<div>
  <h1>Kendo Learning</h1>
  <div class="container">
    @for (course of courses; track course) {
      <app-course-card [course]="course" />
    }
  </div>
</div>

Remarque : Oui, nous utilisons le nouveau Bloc de rendu angulaire 17 @pour la fonctionnalité

Enregistrez les modifications et rechargez la page. Ouais! Notre liste de cours est désormais rendue avec les données dynamiques du tableau !

La page d'apprentissage du Kendo présente deux cours

Parfait, nous avons réduit le code en double et notre composant récupère dynamiquement de nouvelles données. Mais attendez une minute : à quel point est-il réellement flexible ? Que se passe-t-il si nous souhaitons ajouter une nouvelle section sous le titre, comme une description, un auteur ou une bannière de réduction, ou même une nouvelle section ? Nous aurions besoin de changer le type de cours et également de modifier à nouveau le modèle. Cela ne semble pas très flexible pour les changements futurs.

Comment pouvons-nous rendre notre composant plus adaptable aux changements de mise en page ? C’est simple! Angular nous permet d’utiliser <ng-content> au sein de nos composants, fonctionnant comme des espaces réservés qui peuvent être remplis dynamiquement avec du HTML ou d’autres composants. Cette approche est connue dans l’écosystème Angular sous le nom de « projection de contenu ». Plongeons-y.

<ng-content> fonctionne de la même manière que HTML <slot>. En savoir plus sur machines à sous.

Qu’est-ce que la projection de contenu ?

Avant de continuer, qu’est-ce que la projection de contenu exactement ? Le <ng-content> La directive transforme notre composant en un conteneur pouvant inclure dynamiquement du HTML ou d’autres composants, fonctionnant de la même manière que le natif slot élément dans les composants Web. <ng-content> projette tous les éléments enfants dans la zone spécifiée au sein du composant.

La projection de contenu offre également des fonctionnalités supplémentaires, telles que la possibilité de travailler avec plusieurs emplacements et d’utiliser des alias pour spécifier où le contenu doit être projeté. Au lieu de simplement en parler, mettons cette puissante fonctionnalité en action en refactorisant notre modèle de cours pour utiliser la projection de contenu !

En savoir plus sur projection de contenu.

Utiliser la projection de contenu

Ouvrez le course.component.html déposer. Pour incorporer une projection de contenu pour le titre du cours, remplacez le code existant du titre du cours par le <ng-content> étiqueter. Cela vous permettra d’insérer dynamiquement du contenu personnalisé, incluant un titre ou tout autre élément, à l’endroit où <ng-content> est utilisé dans le modèle du composant.

<div class="course-container">
  <div class="course-thumbnail">
    <img [src]="course().image"/>
    <div class="course-status">
      New
    </div>
  </div>
  <ng-content></ng-content>
  <div class="course-footer">
    <span>🕧 {{ course().timeSpan }}</span>
    <span>{{course().rank}} ⭐</span>
  </div>
</div>

Pour utiliser la projection de contenu dans le app.component.html nous fournissons le contenu que nous souhaitons projeter à l’intérieur des balises d’ouverture et de fermeture de votre <course> composant.

Exemple:

<div>
  <h1>Kendo Learning</h1>
  <div class="container">
    @for (course of courses; track course) {
      <app-course-card [course]="course">
        <h3 class="title">{{ course.title }}</h3>
        <span>Author: Telerik</span>
      </app-course-card>
    }
  </div>
</div>

Enregistrez les modifications et rechargez ! Tada!!! Nous avons ajouté un nouvel élément au composant cours sans avoir besoin de le modifier !! Ouais!! 🚀

Le cours affiche le titre comme Angular 17 bientôt 18 !, et l'auteur : Telerik

Ok, je pense que nous pouvons nous améliorer un peu plus en ajoutant plusieurs emplacements pour chaque zone. Refactorisons et utilisons plusieurs emplacements !!

Utiliser plusieurs emplacements

Premièrement, nous devons nettoyer le course-card.component.ts en supprimant la propriété input car nous n’en avons plus besoin. Puis dans course-card.component.html nous devons remplacer les liaisons par <ng-content> pour l’image, le titre et le pied de page du cours.

<div class="course-container">
  <div class="course-thumbnail">
    <ng-content></ng-content>
    <div class="course-status">
      New
    </div>
  </div>
  <ng-content></ng-content>
  <div class="course-footer">
   <ng-content></ng-content>
  </div>
</div>

Ensuite, ouvrez le app.component.html et projeter l’image, la durée et le classement.

<div>
  <h1>Kendo Learning</h1>
  <div class="container">
    @for (course of courses; track course) {
      <app-course-card>
        <img [src]="course.image"/>
        <h3 class="title">{{ course.title }}</h3>
        <span>Author: Telerik</span>
        <span>🕧 {{ course.timeSpan }}</span>
        <span>{{course.rank}} ⭐</span>
      </app-course-card>
    }
  </div>
</div>

Enregistrez les modifications, et tada !!! 😭 Tout est cassé !!!

l'image n'est pas alignée et les titres ne s'affichent pas

Attends une minute!! Si je ne me trompe pas, j’ai ajouté un ng-content dans chaque section et projeté le contenu de l’application. Pourquoi Angular projette-t-il tout le contenu dans un seul conteneur ng ?

Eh bien, par défaut, Angular projette tous les éléments dans le premier ng-content. Nous devons donc trouver un moyen de dire à Angular quel élément de contenu appartient à quel ng-content fente.

Angulaire fournit le select attribut pour indiquer le contenu à projeter en fonction d’un sélecteur CSS, vous permettant de déclarer un nom pour des zones spécifiques. Exemple:

<ng-content select="my-nice-area"></ng-content>

Mais je pense que nous pouvons être un peu plus précis et éviter les erreurs. Au lieu d’utiliser une chaîne, nous pouvons fournir une directive pour chaque zone afin de faciliter la projection de contenu basé sur la directive !

En savoir plus sur plusieurs espaces réservés de contenu.

Tout d’abord, générez une directive pour chaque section : thumbnail-area, title-area et footer-areaà l’aide de la CLI.

ng g d /directives/thumbnail-area
CREATE src/app/directives/thumbnail-area.directive.ts (186 bytes)

ng g d /directives/title-area     
CREATE src/app/directives/title-area.directive.ts (178 bytes)

ng g d /directives/footer-area
CREATE src/app/directives/title-area.directive.ts (178 bytes)

Ensuite, importez les directives ThumbnailAreaDirective, FooterAreaDirective, TitleAreaDirective dans le CourseCardComponent:

@Component({
  selector: 'app-course-card',
  standalone: true,
  imports: [ThumbnailAreaDirective, FooterAreaDirective, TitleAreaDirective],
  templateUrl: './course-card.component.html',
  styleUrl: './course-card.component.css'
})
export class CourseCardComponent {

}

Ensuite, en utilisant le select attribut, ajoutez la directive pour demander à mon ng-content pour prendre l’élément qui correspond à la directive. Mettez à jour la mise en page HTML dans notre composant de carte de cours pour utiliser les directives :

Le code final ressemble à ceci :

<div class="course-container">
  <div class="course-thumbnail">
    <ng-content select="appThumbnailArea"></ng-content>
  <ng-content></ng-content>
    <div class="course-status">
      New
    </div>
  </div>
  <ng-content select="appTitleArea"></ng-content>
  <div>
   <ng-content select="appFooterArea"></ng-content>
  </div>
</div>

Code source complet cours-card.component.ts.

En savoir plus sur Espace réservé à plusieurs contenus.

Enfin, mettez à jour le HTML dans app.component.html utiliser le ng-container avec la directive spécifique.

<div>
  <h1>Kendo Learning</h1>
  <div class="container">
    @for (course of courses; track course) {
      <app-course-card>
        <ng-container appThumbnailArea>
          <img [src]="course.image" [alt]="course.title" />
        </ng-container>

        <ng-container appTitleArea>
          <h3 class="title">{{ course.title }}</h3>
          <span>Author: Telerik</span>
        </ng-container>

        <ng-container appFooterArea>
          <span>🕧 {{ course.timeSpan }}</span>
          <span>{{ course.rank }} ⭐</span>
        </ng-container>
      </app-course-card>
    }
  </div>
</div>

Code source complet pour app.component.html.

Enregistrez les modifications, et tada ! Oui! Nous avons projeté le contenu exactement là où nous le souhaitions ! 🥰

Sur la page Kendo Learning, les cartes affichent l'image, le nouveau, le titre, l'auteur, l'heure avec l'icône, l'icône étoile

résumer

Nous avons commencé notre voyage en discutant de la façon de créer des composants hautement flexibles dans Angular. Nous avons commencé par les bases, en utilisant les entrées, puis sommes passés à la projection de contenu et à l’utilisation du <ng-content> directive peut transformer nos composants en conteneurs polyvalents.

Nous avons franchi une étape suivante en utilisant la puissance du select attribut, qui améliore la projection de contenu en dirigeant un contenu spécifique vers des emplacements désignés, en fonction de sélecteurs ou de directives CSS.

J’espère que cet article vous aidera à créer des composants flexibles et à comprendre comment des composants comme la carte kendo ont été construits ! 🚀 (J’aime comprendre comment construire quelque chose à partir de zéro, même si je préfère utiliser une bibliothèque de composants pour faciliter mon travail !)

Essayez Kendo UI pour Angular




Source link