Création des premiers composants Angular et realisation de l'interface

Par dbeulze, 13 février, 2025

Nouveau blog sur l'application mobile réalisée en Angular

Dans ce nouveau blog, nous allons poursuivre le développement de notre application Angular.

Création des premiers composants Angular et réalisation de l'interface

Dans un premier temps, nous allons réaliser les composants nécessaires pour l'application.

La commande suivante permet de générer un composant à l'aide du CLI Angular :

ng generate component nom_composant
Pour cette application, nous allons créer les composants qui seront utiles pour la page principale.
ng generate component composants/bouton
ng generate component composants/carte-lecon
ng generate component composants/badge

Vous verrez que le CLI Angular créera un dossier composants/ avec les composants générés.

Pour simplifier la création de l'interface utilisateur, nous allons utiliser Bootstrap.

npm install bootstrap bootstrap-icons

Une fois installé, nous devons indiquer que le projet doit utiliser Bootstrap.

"styles": [
  "node_modules/bootstrap/scss/bootstrap.scss",
  "node_modules/bootstrap-icons/font/bootstrap-icons.css"
],
"scripts": [
  "node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"
]

Un composant

Tous les composants que vous allez générer ressembleront à ceci:

// Exemple avec le composant Badge
@Component({
  selector: 'app-badge',
  imports: [],
  templateUrl: './badge.component.html',
  styleUrl: './badge.component.css'
})
export class BadgeComponent {
  @Input() title: string = 'Badge';
}
  1. selector : Le nom que prendra la balise HTML de votre composant.
  2. imports : Les éléments que vous importerez à l'avenir.
  3. templateUrl : Le fichier HTML sur lequel il doit pointer (vous pouvez aussi y placer du code HTML directement).
  4. styleUrl : Le fichier CSS sur lequel il doit pointer (comme pour templateUrl, vous pouvez y placer du CSS directement).
  5. export class BadgeComponent : C'est le corps de votre composant.

Le composant Badge

Nous allons commencer par le composant le plus simple à ce jour : le Badge.

Dans badge.component.ts, nous allons créer un attribut title de type string avec l'annotation @Input() :

@Input() title: string = "Badge"; // <-- Badge sera le texte par defaut 

Cela permet d'ajouter un paramètre (title) lorsque nous instancierons le composant, afin de pouvoir le définir depuis son composant parent.

Dans badge.component.html, nous allons placer notre attribut title et définir son style CSS dans badge.component.css :

<p>{{title}}</p>
p{
  margin: 0;
  color: white;
  background-color: rgb(255 255 255 / 25%);
  padding: 1vh 2vh;
  border-radius: 20px;
  font-size: 12px;
}

Super !!! Votre composant Badge est terminé. Pour l'essayer, vous pouvez ajouter la balise suivante dans votre app.component.html :

<app-badge title="Facile"></app-badge>

Le composant Bouton

C'est le même concept que pour le composant précédent. Nous allons commencer par y définir ses attributs :

  1. title : De type string avec l'annotation @Input().
  2. colorText : De type string avec l'annotation @Input().
  3. onClick : De type EventEmitter<void> avec, cette fois-ci, l'annotation @Output().

Votre bouton.component.ts devrait ressembler à ceci :

@Component({
  selector: 'app-bouton',
  imports: [],
  templateUrl: './bouton.component.html',
  styleUrl: './bouton.component.css'
})
export class BoutonComponent {
  @Input() title: string = "bouton";
  @Input() colorText: string = "";
  @Output() onClick: EventEmitter<void> = new EventEmitter();
  click() {
    this.onClick.emit();
  }
}

L'annotation @Output() dans Angular est utilisée pour émettre des événements vers le composant parent.
Elle fonctionne avec un EventEmitter, permettant ainsi au composant enfant d'envoyer des données ou de notifier
des changements au parent lorsqu'un événement se produit.

Dans notre cas, cela permet de capturer le clic afin d'exécuter une fonction définie dans le composant parent depuis notre composant Bouton.

Dans votre fichier bouton.component.html, ajoutons un bouton :

<button [style.color]="colorText" (click)="click()">{{title}}</button>

Comme vous pouvez le voir, nous avons ajouté quelques éléments supplémentaires.

Pour obtenir un rendu plus esthétique, j'ai décidé de modifier la couleur du texte du bouton.
Cette couleur sera définie par le parent via l'attribut colorText, qui sera appliqué grâce à la directive Angular [style.color].
De plus, l'événement (click) permettra d'exécuter la fonction click() de mon composant.

Dans votre fichier bouton.component.css, ajoutons cette classe :

button {
  border: none;
  border-radius: 20px;
  padding: 1vh 2vh;
  font-weight: 600;
}

Super, votre composant bouton est terminé !!! Passons maintenant au dernier composant de notre page principale, le plus complexe à ce jour.

Création du composant CarteLeconComponent

Ce composant sera utilisé pour afficher une leçon avec un titre, une description et un niveau de difficulté.

Structure du fichier TypeScript (carte-lecon.component.ts)

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

@Component({
  selector: 'app-carte-lecon', 
  imports: [
    BoutonComponent,
    BadgeComponent,
    NgIf
  ],
  templateUrl: './carte-lecon.component.html',
  styleUrls: ['./carte-lecon.component.css']
})
export class CarteLeconComponent implements AfterViewInit {
  color: string = "#6c6c6c"; // Couleur par défaut du fond de la carte
  @Input() add: boolean = false; // Mode d'ajout d'exercice
  @Input() title: string = ""; // Titre de la leçon
  @Input() niveau: string = ""; // Niveau de difficulté de la leçon
  @Input() description: string = ""; // Description de la leçon

  colorList: string[] = [
    "#6A89CC", "#568c95", "#B8E994", "#FA983A", "#E55039", "#F8C291", "#E58E26",
    "#3B3B98", "#546DE5", "#786FA6", "#5D6D7E", "#6D9886", "#B56576", "#775A6F",
    "#4A6374", "#9A4444", "#D4A373", "#3E5C76", "#A79277", "#556B2F", "#855C75",
    "#6C5B7B", "#8E7AB5", "#B565A7", "#457B9D", "#315C69", "#C08497", "#826AED",
    "#4E8098", "#9D8189"
  ];

  ngAfterViewInit(): void {
    const randomIndex = Math.floor(Math.random() * this.colorList.length);
    this.color = this.colorList[randomIndex];
  }
}

Explication du code

  1. Les @Input() permettent au parent de transmettre des valeurs dynamiques au composant.
  2. Choix aléatoire d'une couleur de fond à partir de colorList lors de l'initialisation.

Création du fichier HTML (carte-lecon.component.html)

<div [style.background]="color" class="scale-in-top card-custom container d-flex justify-content-between w-100 gap-3">
  <!-- Mode Ajout d'exercice -->
  <div *ngIf="add" class="d-flex flex-column align-items-center justify-content-center w-100">
    <i class="bi bi-plus-square"></i>
    <p>Ajouter un exercice</p>
  </div>

  <!-- Mode Affichage d'une leçon -->
  <div *ngIf="!add" class="row d-flex flex-column h-100 justify-content-between gap-4">
    <div class="d-flex flex-column gap-2">
      <h4 *ngIf="title.length > 0">{{title}}</h4>
      <p *ngIf="description.length > 0" class="description">{{description}}</p>
    </div>
    <app-bouton [colorText]="color" title="Lancer"></app-bouton>
  </div>

  <!-- Badge du niveau -->
  <div class="row d-flex flex-column h-100 justify-content-between">
    <app-badge *ngIf="niveau.length > 0" [title]="niveau"></app-badge>
  </div>
</div>

Ajout du fichier CSS (carte-lecon.component.css)

Dans ce fichier, nous allons définir le style du composant pour améliorer son apparence et assurer une bonne mise en page.

.card-custom {
  width: 100%;
  height: 100%;
  min-height: 160px;
  border-radius: 15px;
  padding: 2vh;
  transition: 0.3s;
}

p {
  color: white;
  margin: 0;
}

h4 {
  color: white;
}

.description {
  color: #cccccc;
}

i {
  font-size: 5vh;
  color: #ffffff;
}

Utilisation du composant dans l'application

Maintenant que notre composant est prêt, nous allons l'intégrer dans notre application:

<app-carte-lecon
  [title]="'Introduction à Angular'"
  [description]="'Apprenez les bases du framework Angular.'"
  [niveau]="'Débutant'">
</app-carte-lecon>

<app-carte-lecon [add]="true"></app-carte-lecon>

Super, votre composant CarteLeçon est terminé !!!

Maintenant, nous allons créer notre page principale (app.component.html)

Dans celle-ci, nous allons créer de fausses cartes de leçon pour tester tout cela :

<main class="main">
  <div class="h-100 w-100 d-flex flex-column gap-3 p-2 overflow-auto">

    <app-carte-lecon title="L'encan silencieux" description=" Un exercice d'itération en plusieurs langages" niveau="Intermédiaire" ></app-carte-lecon>

    <app-carte-lecon title="Les boucles infinies" description="Comprendre et éviter les pièges des boucles infinies" niveau="Débutant"></app-carte-lecon>

    <app-carte-lecon title="Les fonctions récursives" description="Explorer la récursion et ses applications pratiques" niveau="Intermédiaire"></app-carte-lecon>

    <app-carte-lecon title="Optimisation d'algorithmes" description="Techniques d'amélioration des performances des algorithmes" niveau="Avancé"></app-carte-lecon>

    <app-carte-lecon title="Manipulation des tableaux" description="Méthodes de tri et de filtrage en programmation" niveau="Débutant"></app-carte-lecon>

    <app-carte-lecon title="Programmation orientée objet" description="Principes de l'encapsulation, héritage et polymorphisme" niveau="Intermédiaire"></app-carte-lecon>

    <app-carte-lecon title="Les promesses et async/await" description="Maîtriser l'asynchronisme en JavaScript et TypeScript" niveau="Avancé"></app-carte-lecon>

    <app-carte-lecon title="Créer un jeu en console" description="Développement d'un mini-jeu interactif en ligne de commande" niveau="Débutant"></app-carte-lecon>

    <app-carte-lecon title="Les structures de données" description="Comprendre les listes chaînées, piles et files" niveau="Intermédiaire"></app-carte-lecon>

    <app-carte-lecon title="Introduction aux API REST" description="Consommer et interagir avec des API REST en Angular" niveau="Intermédiaire"></app-carte-lecon>

    <app-carte-lecon title="Test Driven Development (TDD)" description="Écrire des tests unitaires avant d'écrire le code" niveau="Avancé"></app-carte-lecon>

    <app-carte-lecon [add]="true" ></app-carte-lecon>

  </div>
</main>
<router-outlet />

Résultat

Votre application devrait ressembler à ceci :

On se retrouve la semaine prochaine pour le prochain blog, qui portera sur la gestion des leçons et du contenu dynamique (via YML).

Commentaires1

nrainvillejacques

il y a 1 mois

J'ai bien aimé ton article, cela me donne envie de créer une version mobile pour une application que j'ai moi même réalisé avec Angular.

Par contre j'ai une question, pour tout ce qui est notification sait-tu s'il éxiste un moyen pour les faire fonctionner nativement avec un pwa comme ici ou bien doit-t-on utiliser autre chose

Encore une fois, merci pour ton article