3. Les components / composants

0

Dans ce chapitre, on va expliquer ce qu’est un composant. Pour cela, on va regarder en détail le code du composant de base qui est créé lors de la génération d’un nouveau projet Angular. Puis, on va créer et utiliser un premier composant Angular qui va ressembler à ça:

Image d'une carte à jouer.

Pour rappel: cette série de blogs s’inscrit dans une longue lignée de tutos, dont le fil rouge est la création d’une application de visualisation et gestion de cartes à collectionner de type Pokémon, Magic, YuGi ou autres. Et ces nouveaux tutos sont également présents sous format de vidéo longues sur YouTube, ou en format court sur TikTok.

Dans le dernier chapitre, on a vu comment créer un projet Angular. Donc je pars du principe que vous avez un projet prêt à être utilisé, et pour commencer, je vous demanderai d’ouvrir votre éditeur de code avec et de naviguer dans le dossier « src/app ».

Fichiers src/app

Commençons par définir ce qu’est un « component » (composant en français). Eh bien, vous pouvez considérer un composant comme étant une brique de votre application qui va s’occuper d’un aspect bien spécifique de votre app, et qui se charge de définir le contenu, le style et le comportement de cette brique.

Les fichiers d'un composant

Ici, on voit qu’un composant est composé de ces 4 fichiers: un fichier « css » qui va contenir les styles spécifiques à ce composant, un fichier « html » qui contient le rendu du composant, un fichier « spec.ts » où on retrouvera des tests, et pour finir, un fichier « .ts »qui va définir le comportement de notre composant.

Donc, si on regarde notre projet de gestion de cartes à jouer, on pourrait avoir un composant carte, un composant « barre-de-recherche » et un composant « page-principale » qui serait composé d’une « barre-de-recherche » et d’une série de cartes.

Composition de notre app

Quand on regarde le code source de notre application, et les explications que je viens de donner, on pourrait se dire qu’un composant possède toujours 4 fichiers, mais ce n’est pas le cas. Pour être précis, le seul fichier qui est nécessaire est le fichier « .ts ». Un tel composant minimal ressemble à ça:

app.component.ts
import { Component } from '@angular/core';

@Component({
	selector: 'app-root',
	standalone: true,
	template: ''
})
export class AppComponent {
}

Un composant Angular est une simple classe Typscript à laquelle on rajoute le décorateur @Component, qui prend différents paramètres en entrée. Le premier paramètre est le nom de la balise qu’on pourra utiliser dans notre HTML pour y afficher notre composant. Donc ici, la balise à utiliser est la balise <app-root /> , et si on regarde le fichier « index.html », on voit que celui-ci contient effectivement pour seul élément dans le body, le tag « app-root ».

démo app-root dans le fichier index.html

Ensuite, nous avons le paramètre « standalone » qui est à « true ». Dans ce cours, on va uniquement parler de composants « standalone », et donc vous verrez ce paramètre toujours à « true ». Dans les premières versions d’Angular, un composant devait systématiquement vivre à l’intérieur d’un module qui gérait tous les imports des différents composants et de leur dépendances. Il y a quelques années, Angular a introduit la notion de composants « standalone », donc des composants qui peuvent être utilisés sans avoir besoin d’un module.

On ne parlera que de composants « standalone » dans ce cours, mais si vous avez des vieilles applications à maintenir qui utilisent encore NgModule, vous pouvez jeter un coup d’oeil à mes vieilles vidéos sur YouTube pour comprendre comment utiliser des composants non-standalone.

Pour finir le décorateur @Component prend encore le paramètre « template » qui va contenir le HTML que notre composant doit afficher à l’écran. Donc, par exemple, on pourrait ajouter la valeur <h1>Hello World</h1> au paramètre « template »:

app.component.ts
import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    standalone: true,
    template: '<h1>Hello World</h1>'
})
export class AppComponent {

}

Si on regarde le résultat dans notre navigateur, on voit que Hello World est bien affiché à l’écran.

Hello World

Vous pouvez également ajouter du css à votre composant avec le paramètre « styles »:

app.component.ts
import { Component } from '@angular/core';

@Component({
	selector: 'app-root',
	standalone: true,
	template: '<h1>Hello World</h1>',
	styles: `h1 {
		background-color: black;
		color: white;
	}`
})
export class AppComponent {

}

Ce qui nous donne le résultat:

Résultat composant avec css

Et là, vous vous dites sûrement que ça peut vite devenir difficile à lire si on a le html, le css et la typescript dans le même fichier, et vous avez raison. Donc on peut spécifier, tel qu’on l’avait au début, des fichiers qui vont contenir ce HTML et ce css:

Fichiers src/app

Par convention, le fichier html et css ont le même nom que le fichier « .ts » avec leurs extensions respectives, donc ici « app.component.html » et « app.component.css ».

Maintenant on peut copier le html dans le fichier « .html » et le css dans le fichier « .css », et on n’a plus qu’à remplacer le paramètre « template » par le paramètre « templateUrl », qui va être égal à « ./app.component.html ». Le paramètre « styles » va être remplacé par « styleUrl » qui va pointer sur le fichier « ./app.component.css ».

app.component.html
<h1>Hello World</h1>

app.component.css
h1 {
    background-color: black;
    color: white;
}

app.component.ts
import { Component } from '@angular/core';

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

Là, si on sauvegarde le tout et qu’on retourne voir notre navigateur, on voit que le résultat est toujours le même.

Résultat composant avec css

Maintenant, on va créer notre premier composant. Pour cela, on va dans le terminal et là, on a deux choix: Soit vous tapez:

Bash
ng generate component <nom_du_composant>

ou soit vous tapez:

Bash
ng g c <nom_du_composant>

Dans notre cas, on va appeler le composant « playing-card » et on va vouloir stocker ce composant dans un dossier « components » à l’intérieur du dossier app. Pour cela, on va taper:

Bash
ng g c components/playing-card

Si vous ne souhaitez pas générer le fichier de test, vous pouvez également le spécifier avec un « —skip-tests » après le nom de votre composant:

Bash
ng g c components/playing-card --skip-tests

Dans notre cas, on va également générer les tests, car on en reparlera dans un prochain chapitre.

Une fois le composant généré, regardons comment l’afficher sur notre page. Pour cela, on va se rendre dans le dossier « components » et on va jeter un coup d’oeil au contenu du sous-dossier « playing-card »:

Screenshot d'un composant angualr

Si on ouvre le fichier « .ts », on voit que notre composant est une classe qui s’appelle « PlayingCardComponent » et que son sélecteur s’appelle « app-playing-card ».

Donc, pour pouvoir utiliser ce composant dans notre composant principal, nous devons d’abord l’importer dans le fichier « app.component.ts »:

app.component.ts
import { Component } from '@angular/core';
import { PlayingCardComponent } from './components/playing-card/playing-card.component';


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

}

Et là, on peut ouvrir le fichier « app.component.html » et remplacer le code qui s’y trouve par le tag <app-playing-card />:

app.component.html
<app-playing-card />

On sauvegarde, et on peut relancer le projet. Dans le navigateur, vous voyez le contenu par défaut du nouveau composant qui est simplement le nom de celui-ci, donc: « playing-card » suivi du mot « works ».

Example d'utilisation de notre composant

Maintenant, on peut s’attaquer au contenu de notre composant. Tout d’abord on va devoir ajouter quelques images à notre projet. Pour les abonnées Standard et Premium, vous pouvez copier le dossier « img », que vous retrouverez dans le dossier public du code source, dans votre propre dossier public.

Pour les autres, vous pouvez utiliser tout autre image, mais pour pouvoir suivre ce cours le plus simplement possible, je vous recommande de créer un répertoire « img » dans votre répertoire « public » et d’y stocker vos images avec les noms suivants:

Une fois que c’est fait, on va pouvoir créer le contenu de notre fichier « playing-card.component.html »:

playing-card.component.html
<div id="card">
	<div id="inside">
		<header>
			<div class="left">
				<div id="name">My Monster</div>
			</div>
			<div class="right">
				<div id="hp">40 HP</div>
				<img class="energy icon" src="img/electric.png" />
			</div>
		</header>
		<figure id="art">
			<img src="img/pika.png"/>
			<figcaption>N°025 Monster</figcaption>
		</figure>
		<div id="capacities">
			<div class="capacity">
				<div class="main">
					<div class="cost">
						<img class="icon energy" src="img/electric.png" />
						<img class="icon energy" src="img/electric.png" />
					</div>
					<div class="name">Geo Impact</div>
					<div class="damage">60</div>
				</div>
				<div class="description">
					This is a long description of a monster attack.
					Probably something to do with electricity...
				</div>
			</div>
		</div>
	</div>
</div>

Maintenant, ajoutons un peu de css au fichier « playing-card.component.css » pour rendre le tout un peu plus beau:

playing-card.component.css
#card {
    display: block;
    width: 250px;
    padding: 10px;
    border-radius: 10px;
    box-shadow: 5px 5px 10px 0 grey;
    background-color: rgb(221, 221, 221);
}

#inside {
    padding: 5px;
    background-color: rgba(255, 252, 81, 0.676);
}

header {
    display: flex;
    font-size: 16px;
    font-weight: bold;
    margin-bottom: 5px;
}

header .left, header .right {
    display: flex;
    width: 50%;
    align-items: center;
}

header .right {
    flex-direction: row;
    justify-content: flex-end;
    gap: 10px;
}

header .right #hp, header .right img {
    vertical-align: middle;
}

figure#art {
    margin: 0;
    padding: 5px 5px 0 5px;
    width: calc(100% - 10px);
    overflow: hidden;
    background-color: lightgrey;
}

figure#art img {
    width: 100%;
    height: 175px;
    object-fit: cover;
}

figure#art figcaption {
    text-align: center;
    font-size: smaller;
    padding-bottom: 5px;
}

.icon.energy {
    width: 15px;
    height: 15px;
}

#capacities {
    display: flex;
    flex-direction: column;
    justify-content: center;
    height: 100px;
}

.capacity {
    display: flex;
    flex-direction: column;
    margin: 10px 0;
}

.capacity .main {
    display: flex;
    flex-direction: row;
    gap: 10px;
    font-weight: bold;
}

.capacity .main .name {
    flex-grow: 1;
}

.capacity .main .cost {
    display: flex;
    gap: 5px;
    align-items: center;
}

.capacity .description {
    margin-top: 5px;
    font-size: smaller;
}

Et pour finir, on va rajouter quelques styles dans le fichier « styles.css » global de l’application:

styles.css
body, html {
	font-family: Roboto, sans-serif;
	height: 100%;
	background: linear-gradient(45deg, rgb(252, 228, 252), rgb(218, 228, 255));
}

On sauvegarde le tout et on regarde le résultat:

Résultat composant palying-card

Et voilà, nous avons le début de notre carte à jouer qui est affiché à l’écran. On a encore beaucoup de choses à voir avec cette carte, comme, par exemple, le fait de pouvoir lui passer les informations de la carte à afficher en paramètre, mais ça, ce sera le sujet d’un autre chapitre!

Resources

Vous retrouvez ci-dessous un lien vers le code source utilisé dans ce chapitre. Ce lien est uniquement disponible pour les abonnés Standard et Premium. 

Quiz

Répondez au quiz ci-dessous afin de vérifier que vous avez bien compris le contenu de cette leçon. Les quiz sont uniquement disponibles pour les abonnés Standard et Premium.

Laisser un commentaire