TP 1 : Création d'une première application Angular – le site FormaPlus
-
Objectifs
- Ce TP de 6 heures clôt les chapitres Environnement de développement et Créer et configurer un projet Angular. En le réalisant, vous allez apprendre à :
- vérifier un environnement de développement Angular complet : Node.js, npm, Angular CLI, Git et VS Code;
- créer un projet avec
ng new, le lancer avecng serveet le publier sur GitHub dès la première minute ; - identifier le rôle de chaque fichier d'un projet Angular et suivre la chaîne de démarrage
index.html→main.ts→app.config.ts→App; - configurer un projet :
angular.json,tsconfig.json, port du serveur, fichiers d'environnement, réglages de VS Code ; - intégrer une bibliothèque externe avec npm : Bootstrap 5 et Bootstrap Icons;
- découper une page en composants générés avec
ng generate, et les assembler grâce à leurs sélecteurs ; - afficher des données avec l'interpolation
{{ }}, la liaison de propriété[ ], et les blocs@foret@if; - lire les messages d'erreur du compilateur Angular et les corriger ;
- exécuter les tests unitaires générés et les adapter ;
- compiler l'application pour la publication avec
ng buildet tester le résultat avec un serveur web ; - versionner son travail avec Git: un commit à chaque partie, un
README.mdet une version finale étiquetée.
- Prérequis : avoir suivi les leçons Présentation de l'environnement Node.js, Présentation de la CLI Angular, Utiliser Angular avec VS Code et Structure et architecture d'un projet Angular ; connaître les bases de HTML, CSS et Bootstrap 5.
- Avant la séance :
- Node.js (version LTS compatible avec Angular, voir angular.dev/reference/versions) et Angular CLI installés ;
- VS Code avec l'extension Angular Language Service;
- un compte GitHub gratuit et Git installé sur le poste.
- Version d'Angular : ce TP a été réalisé avec Angular 22. Avec une version antérieure à la 20, les fichiers générés portent un suffixe (
app.component.ts,entete.component.ts) et les classes aussi (AppComponent,EnteteComponent) : adaptez simplement les noms, la démarche est identique.
-
Description
- Le centre de formation professionnelle FormaPlus souhaite un site vitrine moderne et adapté aux téléphones pour présenter ses formations aux futurs stagiaires. Le directeur veut une seule page avec : une barre de navigation, une bannière d'accueil, quelques chiffres clés, la liste des formations avec les places restantes, les coordonnées du centre et un pied de page.
- Vous allez réaliser ce site avec Angular et Bootstrap 5. La page est découpée en composants:
| Composant (classe) | Sélecteur | Dossier | Contenu | Partie |
|---|---|---|---|---|
App |
app-root |
src/app/ |
Composant racine : assemble tous les autres | 02 |
Entete |
app-entete |
layout/entete/ |
Barre de navigation Bootstrap, menu repliable sur téléphone | 05 |
Banniere |
app-banniere |
accueil/banniere/ |
Titre, slogan et boutons d'action | 06 |
Contact |
app-contact |
accueil/contact/ |
Adresse, téléphone et e-mail du centre | 06 |
PiedPage |
app-pied-page |
layout/pied-page/ |
Année, nom du centre et version (lus dans l'environnement) | 06 |
ChiffresCles |
app-chiffres-cles |
accueil/chiffres-cles/ |
4 indicateurs affichés avec @for |
07 |
ListeFormations |
app-liste-formations |
formations/liste-formations/ |
Cartes des formations avec @for, @if et un pipe |
07 |
- Résultats attendus : chaque partie se termine par une capture « Résultat attendu ». Comparez votre écran avec cette capture avant de faire votre commit : si le résultat diffère, corrigez avant de passer à la partie suivante.
- Fichier
reponses.md: les questions marquées (R) demandent une réponse écrite, à rédiger au fil du TP dans le fichierreponses.mdà la racine du projet, en rappelant le numéro de la question. - Répartition du temps :
| Partie | Notions travaillées | Durée |
|---|---|---|
| Partie 00 – Vérifier l'environnement et préparer GitHub | node, npm, ng version, git config |
20 min |
| Partie 01 – Créer le projet avec Angular CLI et le publier | ng new, ng serve, git push |
30 min |
| Partie 02 – Explorer la structure du projet | fichiers, chaîne de démarrage, erreurs de compilation | 45 min |
| Partie 03 – Configurer le projet | angular.json, tsconfig.json, environnements, VS Code |
35 min |
| Partie 04 – Intégrer Bootstrap 5 et Bootstrap Icons | npm install, styles et scripts |
30 min |
| Partie 05 – Premier composant : la barre de navigation | ng generate component, imports, encapsulation CSS |
35 min |
| Partie 06 – Construire la page en composants | interpolation, liaison de propriété, environnement | 50 min |
| Partie 07 – Afficher une liste de formations | interface, @for, @if, @empty, pipe |
45 min |
| Partie 08 – Tester et vérifier la qualité | ng test, responsive, Lighthouse |
20 min |
| Partie 09 – Compiler pour la publication | ng build, budgets, dist/ |
30 min |
| Partie 10 – Finaliser le dépôt GitHub et version 1.0 | README.md, git tag |
20 min |
| Total | 6 h |
-
Les 8 étapes de création d'une application Angular
- Quelle que soit l'application, sa création suit toujours les mêmes 8 étapes. Le TP les applique dans cet ordre : gardez ce tableau sous les yeux pour savoir à tout moment où vous en êtes.
| Étape | Ce qu'on fait | Outil / fichier | Partie du TP |
|---|---|---|---|
| 1 | Préparer l'environnement | Node.js, npm, Angular CLI, Git, VS Code | Partie 00 |
| 2 | Créer le projet | ng new, ng serve |
Partie 01 |
| 3 | Comprendre la structure | index.html, main.ts, app.config.ts, app.ts |
Partie 02 |
| 4 | Configurer le projet | angular.json, environments/, .vscode/ |
Partie 03 |
| 5 | Ajouter une bibliothèque | npm install, angular.json |
Partie 04 |
| 6 | Découper l'interface en composants | ng generate component, imports |
Parties 05 et 06 |
| 7 | Afficher les données | {{ }}, [ ], @for, @if, pipes |
Parties 06 et 07 |
| 8 | Tester, compiler et publier | ng test, ng build, git tag |
Parties 08 à 10 |
-
Étape 1 Préparer l'environnement
- Angular CLI est un programme Node.js : sans Node.js et npm, aucune commande
ngne fonctionne. On vérifie les versions avant de commencer.
node -v
npm -v
ng version
git --version
-
Étape 2 Créer le projet
ng newcrée le dossier du projet, installe les dépendances et initialise Git.ng servecompile et sert l'application, puis la recharge à chaque sauvegarde.
ng new forma-plus --style=css --ssr=false
cd forma-plus
ng serve -o
-
Étape 3 Comprendre la structure
- Le navigateur charge
index.html, qui contient la balise vide<app-root>.main.tsdémarre l'application avec le composant racineApp, dont le sélecteur est justementapp-root.
// src/main.ts
bootstrapApplication(App, appConfig)
.catch((err) => console.error(err));
-
Étape 4 Configurer le projet
angular.jsonindique à la CLI comment compiler et servir le projet. Les fichiers d'environnement contiennent les valeurs qui changent entre le développement et la production.
// src/environments/environment.ts
export const environment = {
production: true,
nomCentre: 'FormaPlus',
};
-
Étape 5 Ajouter une bibliothèque
- On installe la bibliothèque avec npm, puis on déclare ses fichiers CSS et JavaScript dans
angular.jsonpour qu'ils soient inclus dans la compilation.
npm install bootstrap bootstrap-icons
-
Étape 6 Découper l'interface en composants
- Chaque zone de la page devient un composant généré par la CLI. Pour l'afficher, on l'ajoute dans les
importsdu composant parent, puis on place sa balise dans le template du parent.
ng generate component layout/entete # forme courte : ng g c layout/entete
-
Étape 7 Afficher les données
- Les données sont des propriétés de la classe du composant. Le template les affiche avec
{{ }}, les lie aux attributs avec[ ], et répète ou conditionne des blocs avec@foret@if.
@for (f of formations; track f.id) {
<h5>{{ f.titre }}</h5>
@if (f.nouveau) { <span class="badge text-bg-success">Nouveau</span> }
}
-
Étape 8 Tester, compiler et publier
ng testexécute les tests unitaires,ng buildproduit les fichiers optimisés dansdist/, et une étiquette Git marque la version livrée.
ng test --watch=false
ng build
git tag v1.0
À retenir : les étapes 1 à 5 se font une seule fois au début du projet. Les étapes 6 et 7 se répètent pour chaque nouvelle zone de l'interface, en suivant toujours le cycle générer le composant → écrire la classe → écrire le template → l'importer dans le parent → vérifier dans le navigateur → commit. L'étape 8 intervient avant chaque livraison.
-
Travail à réaliser
-
Partie 00 Vérifier l'environnement et préparer GitHub
- Objectif : s'assurer que tous les outils sont installés et configurés avant de créer le projet. Un outil manquant découvert en milieu de séance fait perdre beaucoup de temps.
- Q0.1. Ouvrir un terminal (Invite de commandes, PowerShell ou le terminal de VS Code) et exécuter les commandes de l'étape 1. Noter les quatre versions obtenues : elles serviront dans le
README.md.- si
ngn'est pas reconnu :npm install -g @angular/cli, puis fermer et rouvrir le terminal ; - si PowerShell affiche « l'exécution de scripts est désactivée » : voir la leçon Erreur exécution de script sur Visual Studio Code ;
- si
ng versionsignale une version de Node.js non prise en charge : installer une version LTS compatible ; - à la première commande
ng, la CLI peut demander si vous acceptez de partager des statistiques anonymes : répondreN.
- si
- Q0.2. Dans VS Code, ouvrir le panneau Extensions (Ctrl + Maj + X) et vérifier que Angular Language Service et Prettier sont installés.
- Q0.3. Créer un dossier de travail sans espace ni accent dans son chemin, par exemple
C:\projets-angular(Windows) ou~/projets-angular(Linux, macOS). Pourquoi faut-il éviter les espaces et les accents dans les chemins des projets ? - Q0.4. Configurer Git une seule fois sur le poste avec votre nom et l'adresse e-mail de votre compte GitHub. Si c'est déjà fait dans un TP précédent, vérifier avec
git config --global --list.
git config --global user.name "Prénom Nom"
git config --global user.email "adresse@exemple.com"
git config --global --list
- Q0.5. Sur github.com/new, créer un dépôt nommé
forma-plus, sans cocher « Add a README », « .gitignore » ni « license » : Angular CLI va créer ces fichiers. Si le dépôt est privé, inviter l'enseignant comme collaborateur (Settings → Collaborators).
Authentification et mots de passe : lors du premier
Règle de sécurité : un mot de passe ou un jeton ne doit jamais être écrit dans le code, dans
git push, GitHub n'accepte plus le mot de passe du compte. Connectez-vous par le navigateur quand Git le propose (Git Credential Manager ou VS Code), ou utilisez un Personal Access Token (Settings → Developer settings → Personal access tokens) à la place du mot de passe. Copiez le jeton immédiatement : GitHub ne l'affiche qu'une seule fois.Règle de sécurité : un mot de passe ou un jeton ne doit jamais être écrit dans le code, dans
README.md ou dans un fichier envoyé sur GitHub.Règle du TP : un commit et un push à la fin de chaque partie.
Chaque partie se termine par un encadré « Git » qui donne le message de commit attendu. L'historique des commits fait partie de la note : un dépôt qui ne contient qu'un seul commit déposé en fin de séance n'obtient aucun point sur le critère Git.
Question de réflexion (R) : si votre application ne compile plus après la partie 06, comment l'historique des commits vous permet-il de retrouver la dernière version qui fonctionnait ?
Chaque partie se termine par un encadré « Git » qui donne le message de commit attendu. L'historique des commits fait partie de la note : un dépôt qui ne contient qu'un seul commit déposé en fin de séance n'obtient aucun point sur le critère Git.
Question de réflexion (R) : si votre application ne compile plus après la partie 06, comment l'historique des commits vous permet-il de retrouver la dernière version qui fonctionnait ?
-
Résultat attendu à la fin de la partie 00
-
Partie 01 Créer le projet avec Angular CLI et le publier
- Objectif : créer le projet
forma-plus, le lancer, puis l'envoyer immédiatement sur GitHub. - Q1.1. Se placer dans le dossier de travail (
cd C:\projets-angular), puis simuler la création du projet avec l'option--dry-run. (R) Combien de fichiers seraient créés ? Le dossierforma-plusexiste-t-il après la commande ? Pourquoi ?
ng new forma-plus --style=css --ssr=false --dry-run
- Q1.2. Créer réellement le projet avec la même commande, sans
--dry-run. Si la CLI demande quels outils d'intelligence artificielle configurer, choisir None. Observer les trois étapes affichées dans le terminal : création des fichiers (CREATE), installation des paquets, initialisation de Git. - Q1.3. Entrer dans le dossier et ouvrir le projet dans VS Code. Répondre « Oui » si VS Code demande de faire confiance aux auteurs du dossier.
cd forma-plus
code .
# dans le terminal de VS Code
git log --oneline
git branch
- Q1.4. (R) Dans le terminal de VS Code (Ctrl + `), exécuter
git log --onelineetgit branch. Quel est le message du premier commit ? Qui l'a créé ? Comment s'appelle la branche ? - Q1.5. Lancer le serveur de développement avec
ng serve -o. La page d'accueil par défaut d'Angular s'ouvre surhttp://localhost:4200. Garder ce terminal ouvert pendant tout le TP et en ouvrir un second (bouton + du panneau) pour les autres commandes. - Q1.6. À la racine du projet, créer le fichier
reponses.md(titre « TP 1 Angular – Réponses », votre nom, puis vos réponses aux questions Q0.3, Q1.1 et Q1.4) et le dossiercaptures/. Faire une capture de la page d'accueil et l'enregistrer souscaptures/01_page_par_defaut.png. - Q1.7. Dans le second terminal, relier le projet au dépôt GitHub créé en partie 00 et l'envoyer. Remplacer
VOTRE-COMPTEpar votre nom d'utilisateur GitHub.
git add .
git commit -m "Partie 01 : création du projet FormaPlus avec Angular CLI"
git branch -M main
git remote add origin https://github.com/VOTRE-COMPTE/forma-plus.git
git push -u origin main
# Vérifications utiles
git status # fichiers modifiés
git log --oneline # historique des commits
git remote -v # adresse du dépôt GitHub
- Q1.8. (R) Actualiser la page du dépôt sur GitHub. Le dossier
node_modules/apparaît-il ? Ouvrir le fichier.gitignoredu projet et trouver la ligne qui l'exclut. Pourquoi ne faut-il jamais envoyer ce dossier sur GitHub ? Envoyer le lien du dépôt à l'enseignant avant de commencer la partie 02.
-
Résultat attendu à la fin de la partie 01
localhost:4200, et projet envoyé sur la branche main du dépôt GitHub.Git – fin de la partie 01 : le commit et le push ont été faits en Q1.7. Vérifier avec
git status qu'il ne reste rien à envoyer (« nothing to commit, working tree clean »).-
Partie 02 Explorer la structure du projet
- Objectif : connaître le rôle de chaque fichier, comprendre comment l'application démarre, puis remplacer la page par défaut par votre propre contenu.
- Voici l'arborescence générée par
ng new(sansnode_modules/) :
forma-plus/
├── .vscode/
│ ├── extensions.json # extensions recommandées
│ ├── launch.json # configuration du débogueur
│ └── tasks.json
├── public/
│ └── favicon.ico
├── src/
│ ├── app/
│ │ ├── app.config.ts
│ │ ├── app.css
│ │ ├── app.html
│ │ ├── app.routes.ts
│ │ ├── app.spec.ts
│ │ └── app.ts
│ ├── index.html
│ ├── main.ts
│ └── styles.css
├── .editorconfig
├── .gitignore
├── .prettierrc
├── angular.json
├── package.json
├── package-lock.json
├── README.md
├── tsconfig.app.json
├── tsconfig.json
└── tsconfig.spec.json
- Q2.1. (R) Recopier et compléter le tableau suivant dans
reponses.md. Ouvrir chaque fichier dans VS Code pour trouver son rôle.
| Fichier | Rôle |
|---|---|
src/index.html |
La page unique de l'application (SPA) ; contient la balise <app-root> |
src/main.ts |
? |
src/app/app.config.ts |
? |
src/app/app.ts |
? |
src/app/app.html |
? |
src/app/app.spec.ts |
? |
src/styles.css |
? |
public/ |
? |
angular.json |
Configuration du projet pour Angular CLI (compilation, serveur, tests) |
package.json |
? |
tsconfig.json |
? |
.gitignore |
? |
- Q2.2. (R) La chaîne de démarrage. Ouvrir successivement
index.html,main.ts,app.config.tsetapp.ts, puis répondre :- quelle balise de
index.htmlest vide ? Que va-t-elle contenir ? - quelle fonction de
main.tsdémarre l'application ? Avec quel composant et quelle configuration ? - dans quel fichier, et avec quelle propriété, le sélecteur
app-rootest-il défini ? - quel provider est déclaré dans
app.config.tspour gérer les URL ?
- quelle balise de
- Q2.3. Dans
app.ts, repérer la ligneprotected readonly title = signal('forma-plus');. Remplacer'forma-plus'par'FormaPlus', enregistrer et observer le navigateur. Dansapp.html, rechercher (Ctrl + F) l'endroit oùtitleest affiché.
Pourquoi
title() avec des parenthèses ? title est un signal: une valeur réactive qu'on lit en l'appelant comme une fonction. Les signals seront étudiés dans le chapitre Data Binding. Dans ce TP, nous utiliserons de simples propriétés de classe, affichées sans parenthèses.- Q2.4. Remplacer tout le contenu de
app.html(environ 300 lignes) par le code ci-dessous à gauche. Dansapp.ts, remplacer seulement la ligneprotected readonly title = …par les deux propriétésnomCentre = 'FormaPlus';etdateCreation = '28/10/2026';, sans toucher aux lignesimportni au tableauimports. Enregistrer et observer le terminal deng serve: (R) quel avertissementNG8113s'affiche ? Que signifie-t-il ?
<!-- src/app/app.html -->
<h1>{{ nomCentre }}</h1>
<p>Mon premier projet Angular, créé le {{ dateCreation }}.</p>
# Avertissement attendu dans le terminal
▲ [WARNING] NG8113: All imports are unused
src/app/app.ts:5:2:
5 │ imports: [RouterOutlet],
// src/app/app.ts (version corrigée en Q2.5)
import { Component } from '@angular/core';
@Component({
imports: [],
selector: 'app-root',
styleUrl: './app.css',
templateUrl: './app.html',
})
export class App {
nomCentre = 'FormaPlus';
dateCreation = '28/10/2026';
}
- Q2.5. Corriger l'avertissement : retirer
RouterOutletdu tableauimports, supprimer la ligneimport { RouterOutlet } …devenue inutile, et retirersignalde la première ligne d'import. Le code doit correspondre à la version de droite ci-dessus. Remplacer aussidateCreationpar la date du jour. - Q2.6. Dans
src/index.html, remplacerlang="en"parlang="fr"et le titre parFormaPlus – Centre de formation. (R) Où ce titre apparaît-il dans le navigateur ? Pourquoilang="fr"est-il important pour les lecteurs d'écran et les moteurs de recherche ? - Q2.7. Provoquer volontairement trois erreurs, l'une après l'autre. Pour chacune, (R) noter le code et le message d'erreur affichés dans le terminal, et dire si VS Code soulignait déjà l'erreur avant l'enregistrement. Corriger chaque erreur avant de passer à la suivante.
| Erreur provoquée | Modification | Message attendu |
|---|---|---|
| a) Faute de frappe dans le template | {{ nomCentr }} dans app.html |
TS2551: Property 'nomCentr' does not exist on type 'App'. Did you mean 'nomCentre'? |
| b) Mauvais type | nomCentre: string = 2026; dans app.ts |
TS2322: Type 'number' is not assignable to type 'string'. |
| c) Accolade manquante | supprimer la dernière } de app.ts |
à relever vous-même |
- Q2.8. (R) Ouvrir
package.json. Quelle est la différence entredependenciesetdevDependencies? Citer un paquet de chaque section. Quelle commande lance le scriptnpm start?
-
Résultat attendu à la fin de la partie 02
index.html. Git – fin de la partie 02 :
git add .
git commit -m "Partie 02 : exploration de la structure du projet"
git push
-
Partie 03 Configurer le projet
- Objectif : lire et modifier les fichiers de configuration, et séparer les réglages de développement et de production grâce aux environnements.
- Q3.1. (R) Ouvrir
angular.jsonet trouver :- le préfixe des sélecteurs (
prefix) et le dossier des sources (sourceRoot) ; - le fichier d'entrée de l'application (
browser) et la liste des feuilles de style globales (styles) ; - la configuration utilisée par défaut par
ng build, puis parng serve(defaultConfiguration).
- le préfixe des sélecteurs (
- Q3.2. Changer le port du serveur de développement : dans
angular.json, ajouter un blocoptionsdans la cibleserve, comme ci-dessous. Arrêterng serve(Ctrl + C) et le relancer. (R) Sur quelle adresse l'application est-elle maintenant servie ? Pourquoi faut-il relancerng serveaprès avoir modifiéangular.json, alors qu'une modification deapp.htmlest prise en compte immédiatement ?
"serve": {
"builder": "@angular/build:dev-server",
"options": {
"port": 4300
},
"configurations": {
...
- Q3.3. (R) Ouvrir
tsconfig.jsonet trouver l'option"strict": true. Quel lien faites-vous avec l'erreur b) de la question Q2.7 ? - Q3.4. Générer les fichiers d'environnement avec la CLI, puis ouvrir
angular.json: (R) quelle section la commande a-t-elle ajoutée dans la configurationdevelopment? Que signifie-t-elle ?
ng generate environments
# Résultat
CREATE src/environments/environment.ts
CREATE src/environments/environment.development.ts
UPDATE angular.json
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.development.ts"
}
]
}
- Q3.5. Compléter les deux fichiers d'environnement :
// src/environments/environment.ts (production)
export const environment = {
production: true,
nomCentre: 'FormaPlus',
version: '1.0.0',
};
// src/environments/environment.development.ts
export const environment = {
production: false,
nomCentre: 'FormaPlus (développement)',
version: '1.0.0-dev',
};
- Q3.6. Utiliser l'environnement dans le composant racine : on importe toujours
environment.ts, et la CLI le remplace automatiquement par la version de développement quand c'est nécessaire. Ajouter un pied de page provisoire dansapp.html. (R) Quel nom de centre s'affiche avecng serve? Pourquoi ?
// src/app/app.ts
import { Component } from '@angular/core';
import { environment } from '../environments/environment';
@Component({
imports: [],
selector: 'app-root',
styleUrl: './app.css',
templateUrl: './app.html',
})
export class App {
nomCentre = environment.nomCentre;
version = environment.version;
dateCreation = '28/10/2026';
}
<!-- à ajouter à la fin de app.html -->
<footer>
{{ nomCentre }} – version {{ version }}
</footer>
Attention : les fichiers d'environnement sont compilés dans le JavaScript envoyé au navigateur. N'importe quel visiteur peut les lire avec les outils de développement. On n'y place jamais de mot de passe, de jeton ou de clé secrète.
- Q3.7. Partager la configuration de l'éditeur avec l'équipe. Créer le fichier
.vscode/settings.jsonci-dessous, puis ajouter"esbenp.prettier-vscode"dans.vscode/extensions.json. Le projet contient déjà un fichier.prettierrc: (R) quelles règles de formatage définit-il ? Désindenter tout le code deapp.ts, enregistrer et observer.
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.tabSize": 2,
"files.autoSave": "afterDelay"
}
{
"recommendations": [
"angular.ng-template",
"esbenp.prettier-vscode"
]
}
-
Résultat attendu à la fin de la partie 03
Git – fin de la partie 03 : vérifier avec
git status que le dossier src/environments/ et le fichier .vscode/settings.json apparaissent bien.
git add .
git commit -m "Partie 03 : configuration (port, environnements, VS Code)"
git push
-
Partie 04 Intégrer Bootstrap 5 et Bootstrap Icons
- Objectif : ajouter une bibliothèque externe au projet avec npm, puis la déclarer dans
angular.json. - Q4.1. Dans le second terminal, installer les deux bibliothèques. (R) Dans quelle section de
package.jsonont-elles été ajoutées ? Quelles versions ont été installées ? Dans quel dossier se trouvent leurs fichiers ?
npm install bootstrap bootstrap-icons
- Q4.2. Déclarer les fichiers de Bootstrap dans
angular.json, dansprojects → forma-plus → architect → build → options: compléter le tableaustyleset ajouter le tableauscripts. (R) Pourquoisrc/styles.cssdoit-il rester en dernier dans la listestyles?
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"node_modules/bootstrap-icons/font/bootstrap-icons.css",
"src/styles.css"
],
"scripts": [
"node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"
]
- Q4.3. Relancer
ng serve(modification deangular.json). Remplacer le contenu deapp.htmlpar la page de test ci-dessous, puis vérifier que les couleurs, l'icône et le bouton s'affichent correctement.
<div class="container py-4">
<h1 class="text-primary"><i class="bi bi-mortarboard-fill"></i> {{ nomCentre }}</h1>
<p class="lead">Mon premier projet Angular, créé le {{ dateCreation }}.</p>
<div class="alert alert-success">
<i class="bi bi-check-circle-fill me-2"></i>Bootstrap 5 et Bootstrap Icons fonctionnent !
</div>
<button class="btn btn-primary" type="button" data-bs-toggle="collapse" data-bs-target="#zoneTest">
<i class="bi bi-eye me-1"></i> Afficher / masquer
</button>
<div class="collapse mt-3" id="zoneTest">
<div class="card card-body">Le JavaScript de Bootstrap fonctionne aussi.</div>
</div>
</div>
<footer class="container text-secondary small">{{ nomCentre }} – version {{ version }}</footer>
- Q4.4. Cliquer sur « Afficher / masquer ». (R) Supprimer temporairement le tableau
scriptsdeangular.json, relancerng serveet recliquer : que se passe-t-il ? Qu'en déduisez-vous sur le rôle debootstrap.bundle.min.js? Remettre le tableauscripts. - Q4.5. (R) On aurait pu inclure Bootstrap avec une balise
<link>vers un CDN dansindex.html. Donner deux avantages de l'installation avec npm dans un projet Angular.
-
Résultat attendu à la fin de la partie 04
Git – fin de la partie 04 : (R)
package.json et package-lock.json ont été modifiés, mais pas node_modules/. Comment un camarade qui clone votre dépôt obtiendra-t-il Bootstrap ?
git add .
git commit -m "Partie 04 : intégration de Bootstrap 5 et Bootstrap Icons"
git push
-
Partie 05 Premier composant : la barre de navigation
- Objectif : générer un composant avec la CLI, l'afficher dans le composant racine, et observer l'encapsulation des styles.
- Q5.1. Simuler puis générer le composant
Entete. (R) Quels sont les quatre fichiers créés et le rôle de chacun ? Dans quel dossier se trouvent-ils ?
ng g c layout/entete --dry-run
ng g c layout/entete
# Résultat
CREATE src/app/layout/entete/entete.css
CREATE src/app/layout/entete/entete.spec.ts
CREATE src/app/layout/entete/entete.ts
CREATE src/app/layout/entete/entete.html
- Q5.2. Compléter la classe et le template du composant :
// src/app/layout/entete/entete.ts
import { Component } from '@angular/core';
@Component({
imports: [],
selector: 'app-entete',
styleUrl: './entete.css',
templateUrl: './entete.html',
})
export class Entete {
nomCentre = 'FormaPlus';
slogan = 'Centre de formation professionnelle';
}
<!-- src/app/layout/entete/entete.html -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary sticky-top">
<div class="container">
<a class="navbar-brand fw-bold" href="#">
<i class="bi bi-mortarboard-fill me-2"></i>{{ nomCentre }}
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#menuPrincipal" aria-controls="menuPrincipal"
aria-expanded="false" aria-label="Afficher le menu">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="menuPrincipal">
<ul class="navbar-nav ms-auto">
<li class="nav-item"><a class="nav-link" href="#accueil">Accueil</a></li>
<li class="nav-item"><a class="nav-link" href="#formations">Formations</a></li>
<li class="nav-item"><a class="nav-link" href="#contact">Contact</a></li>
</ul>
<span class="navbar-text ms-lg-3 d-none d-lg-inline small">{{ slogan }}</span>
</div>
</div>
</nav>
- Q5.3. Placer la balise
<app-entete />tout en haut deapp.htmlet remplacer la page de test par un court paragraphe (garder le pied de page). Enregistrer sans toucher àapp.ts: (R) quel est le code de l'erreur affichée ? Que propose le message pour la corriger ? - Q5.4. Corriger l'erreur : dans
app.ts, importer la classeEnteteet l'ajouter au tableauimportsdu composant racine.
// src/app/app.ts
import { Component } from '@angular/core';
import { environment } from '../environments/environment';
import { Entete } from './layout/entete/entete';
@Component({
imports: [Entete],
selector: 'app-root',
styleUrl: './app.css',
templateUrl: './app.html',
})
export class App {
nomCentre = environment.nomCentre;
version = environment.version;
}
<!-- src/app/app.html -->
<app-entete />
<div class="container py-4">
<p class="lead">
La barre de navigation est maintenant un composant.
</p>
</div>
<footer class="container text-secondary small">
{{ nomCentre }} – version {{ version }}
</footer>
Message d'erreur NG8001 :
C'est l'erreur la plus fréquente quand on débute : un composant enfant doit toujours être déclaré dans les
'app-entete' is not a known element: If 'app-entete' is an Angular component, then verify that it is included in the '@Component.imports' of this component.C'est l'erreur la plus fréquente quand on débute : un composant enfant doit toujours être déclaré dans les
imports du composant parent qui l'utilise. Dans VS Code, Ctrl + . sur la balise propose d'ajouter l'import automatiquement.- Q5.5. Tester l'affichage responsive : ouvrir les outils de développement (F12), activer la barre d'outils des appareils (Ctrl + Maj + M) et choisir une largeur de 390 px. Le menu se replie-t-il derrière le bouton ? S'ouvre-t-il au clic ?
- Q5.6. Observer l'encapsulation des styles:
- ajouter la règle
a { text-transform: uppercase; }dansentete.css: quels liens sont en majuscules ? Ajouter un lien<a href="#">test</a>dansapp.html: est-il en majuscules ? - déplacer la même règle dans
src/styles.css: que change-t-il ? - (R) dans l'onglet Éléments des outils de développement, quels attributs commençant par
_ngcontent-et_nghost-Angular a-t-il ajoutés ? Expliquer à quoi ils servent. - supprimer la règle et le lien de test.
- ajouter la règle
-
Résultat attendu à la fin de la partie 05
Entete affiché par le composant racine : menu horizontal sur ordinateur, menu repliable sur téléphone.Git – fin de la partie 05 :
git add .
git commit -m "Partie 05 : composant Entete (barre de navigation)"
git push
-
Partie 06 Construire la page en composants
- Objectif : créer les autres zones de la page, utiliser la liaison de propriété
[ ], et déplacer le pied de page dans son propre composant. - Q6.1. Générer les trois composants de cette partie :
ng g c accueil/banniere
ng g c accueil/contact
ng g c layout/pied-page
-
La bannière
- Q6.2. Compléter les trois fichiers du composant
Banniere:
// src/app/accueil/banniere/banniere.ts
import { Component } from '@angular/core';
@Component({
imports: [],
selector: 'app-banniere',
styleUrl: './banniere.css',
templateUrl: './banniere.html',
})
export class Banniere {
titre = 'Apprenez un métier, construisez votre avenir';
sousTitre = 'Des formations pratiques en développement, réseaux et design, '
+ 'encadrées par des formateurs du métier.';
lienInscription = 'https://github.com';
inscriptionsOuvertes = true;
}
/* src/app/accueil/banniere/banniere.css */
.banniere {
background: linear-gradient(135deg, #0d6efd 0%, #6610f2 100%);
}
<!-- src/app/accueil/banniere/banniere.html -->
<section id="accueil" class="banniere text-white text-center py-5">
<div class="container py-4">
<h1 class="display-5 fw-bold">{{ titre }}</h1>
<p class="lead col-lg-8 mx-auto">{{ sousTitre }}</p>
<a class="btn btn-light btn-lg me-2" href="#formations">
<i class="bi bi-list-ul me-1"></i> Voir les formations
</a>
<a class="btn btn-outline-light btn-lg" target="_blank"
[href]="lienInscription"
[class.disabled]="!inscriptionsOuvertes">
<i class="bi bi-pencil-square me-1"></i> S'inscrire
</a>
</div>
</section>
- Q6.3. (R) Expérimenter la liaison de propriété:
- remplacer
[href]="lienInscription"parhref="lienInscription"(sans crochets) et survoler le bouton : quelle adresse s'affiche en bas du navigateur ? Expliquer la différence, puis remettre les crochets ; - passer
inscriptionsOuvertesàfalse: que devient le bouton « S'inscrire » ? Que fait[class.disabled]? Remettretrue.
- remplacer
-
Les coordonnées : à vous de jouer
- Q6.4. Dans
contact.ts, ajouter les trois propriétés ci-dessous. Écrire vous-même le templatecontact.htmlen vous inspirant de l'exemple : une section d'identifiantcontact, sur fond gris clair (bg-light), avec un titre « Nous contacter » et une ligne de trois colonnes (adresse, téléphone, e-mail). Le téléphone et l'e-mail doivent être des liens cliquables construits avec une liaison de propriété.
// dans la classe Contact
adresse = 'Avenue Habib Bourguiba, Tunis';
telephone = '+216 71 000 000';
email = 'contact@formaplus.tn';
<!-- exemple pour la colonne « e-mail » -->
<div class="col-md-4">
<i class="bi bi-envelope fs-2 text-primary"></i>
<p class="mt-2">
<a [href]="'mailto:' + email">{{ email }}</a>
</p>
</div>
<!-- téléphone : icône bi-telephone, lien 'tel:' -->
<!-- adresse : icône bi-geo-alt, texte simple -->
-
Le pied de page
- Q6.5. Déplacer le pied de page provisoire de
app.htmldans le composantPiedPage. Le composant lit le nom du centre et la version dans l'environnement, et calcule l'année en cours. (R) Pourquoi le chemin d'import de l'environnement contient-il maintenant trois fois../?
// src/app/layout/pied-page/pied-page.ts
import { Component } from '@angular/core';
import { environment } from '../../../environments/environment';
@Component({
imports: [],
selector: 'app-pied-page',
styleUrl: './pied-page.css',
templateUrl: './pied-page.html',
})
export class PiedPage {
nomCentre = environment.nomCentre;
version = environment.version;
annee = new Date().getFullYear();
}
<!-- src/app/layout/pied-page/pied-page.html -->
<footer class="bg-dark text-white-50 py-4">
<div class="container d-flex flex-column flex-md-row
justify-content-between small">
<span>© {{ annee }} {{ nomCentre }} – Tous droits réservés</span>
<span>Version {{ version }} · Réalisé avec Angular et Bootstrap 5</span>
</div>
</footer>
-
Assembler la page
- Q6.6. Le composant racine ne contient plus de données : il se contente d'assembler les composants. Mettre à jour
app.tsetapp.html:
// src/app/app.ts
import { Component } from '@angular/core';
import { Entete } from './layout/entete/entete';
import { PiedPage } from './layout/pied-page/pied-page';
import { Banniere } from './accueil/banniere/banniere';
import { Contact } from './accueil/contact/contact';
@Component({
imports: [Entete, Banniere, Contact, PiedPage],
selector: 'app-root',
styleUrl: './app.css',
templateUrl: './app.html',
})
export class App {}
<!-- src/app/app.html -->
<app-entete />
<main>
<app-banniere />
<app-contact />
</main>
<app-pied-page />
- Q6.7. Ajouter les styles globaux ci-dessous dans
src/styles.css, puis cliquer sur les liens du menu. (R) Pourquoi ces règles sont-elles placées dansstyles.csset non dansentete.css? À quoi sertscroll-margin-top?
/* src/styles.css : s'applique à toute l'application */
html {
scroll-behavior: smooth;
}
section {
scroll-margin-top: 56px; /* hauteur de la barre de navigation */
}
-
Résultat attendu à la fin de la partie 06
Git – fin de la partie 06 :
git add .
git commit -m "Partie 06 : composants Banniere, Contact et PiedPage"
git push
-
Partie 07 Afficher une liste de formations
- Objectif : décrire les données avec une interface TypeScript, puis afficher une liste avec
@for, des conditions avec@if, et formater un texte avec un pipe. -
Les chiffres clés
- Q7.1. Générer le composant
accueil/chiffres-cles. Sa classe contient un tableau de quatre objets ; le template les affiche en répétant le même bloc avec@for.
// dans la classe ChiffresCles
chiffres = [
{ valeur: '12', libelle: 'Formations', icone: 'bi-journal-code' },
{ valeur: '850', libelle: 'Stagiaires formés', icone: 'bi-people' },
{ valeur: '92 %', libelle: "Taux d'insertion", icone: 'bi-briefcase' },
{ valeur: '25', libelle: 'Entreprises partenaires', icone: 'bi-building' },
];
<!-- chiffres-cles.html -->
<section class="py-5 bg-light">
<div class="container">
<div class="row g-4 text-center">
@for (c of chiffres; track c.libelle) {
<div class="col-6 col-md-3">
<i class="bi fs-1 text-primary" [class]="c.icone"></i>
<div class="fs-2 fw-bold">{{ c.valeur }}</div>
<div class="text-secondary">{{ c.libelle }}</div>
</div>
}
</div>
</div>
</section>
- Q7.2. Afficher
<app-chiffres-cles />juste après la bannière (sans oublier lesimportsdeApp). (R) Combien de fois le bloc entre accolades est-il répété ? Que fait[class]="c.icone"? Les classes écrites dans l'attributclasssont-elles conservées ? -
Le modèle de données
- Q7.3. Générer l'interface
Formationavec la CLI et la compléter. Une interface décrit la forme d'un objet : elle n'existe plus dans le JavaScript compilé, mais TypeScript vérifie que chaque formation la respecte.
ng g i models/formation
# Résultat
CREATE src/app/models/formation.ts
// src/app/models/formation.ts
export interface Formation {
id: number;
titre: string;
description: string;
dureeMois: number;
niveau: string;
icone: string;
nouveau: boolean;
placesRestantes: number;
}
-
La liste des formations
- Q7.4. Générer le composant
formations/liste-formations. Dans sa classe, déclarer le tableauformationstypé avec l'interface. Les deux premières formations sont données ; ajouter vous-même les deux suivantes à partir du tableau ci-dessous.
// src/app/formations/liste-formations/liste-formations.ts
import { Component } from '@angular/core';
import { UpperCasePipe } from '@angular/common';
import { Formation } from '../../models/formation';
@Component({
imports: [UpperCasePipe],
selector: 'app-liste-formations',
styleUrl: './liste-formations.css',
templateUrl: './liste-formations.html',
})
export class ListeFormations {
formations: Formation[] = [
{
id: 1,
titre: 'Développement web et mobile',
description: 'HTML, CSS, Bootstrap, Angular et Flutter pour créer des applications modernes.',
dureeMois: 24,
niveau: 'Technicien supérieur',
icone: 'bi-code-slash',
nouveau: false,
placesRestantes: 6,
},
{
id: 2,
titre: 'Réseaux informatiques',
description: 'Installation, configuration et sécurisation des réseaux d’entreprise.',
dureeMois: 24,
niveau: 'Technicien supérieur',
icone: 'bi-hdd-network',
nouveau: false,
placesRestantes: 0,
},
// formations 3 et 4 : à compléter
];
}
| id | titre | description | dureeMois | niveau | icone | nouveau | placesRestantes |
|---|---|---|---|---|---|---|---|
| 3 | Infographie et design | Création graphique, retouche photo et conception d’interfaces (UI). | 12 | Technicien | bi-palette |
true |
10 |
| 4 | Maintenance informatique | Diagnostic, dépannage et maintenance des postes et périphériques. | 12 | Technicien | bi-tools |
true |
3 |
- Q7.5. Écrire le template. Chaque formation est affichée dans une carte Bootstrap ; le badge « Nouveau » n'apparaît que si
nouveauvauttrue, et le pied de la carte indique les places restantes ou « Complet ».
<!-- src/app/formations/liste-formations/liste-formations.html -->
<section id="formations" class="py-5">
<div class="container">
<h2 class="text-center mb-2">Nos formations</h2>
<p class="text-center text-secondary mb-4">{{ formations.length }} formations proposées cette année</p>
<div class="row g-4">
@for (f of formations; track f.id) {
<div class="col-md-6 col-lg-3">
<div class="card h-100 shadow-sm">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start mb-3">
<i class="bi fs-1 text-primary" [class]="f.icone"></i>
@if (f.nouveau) {
<span class="badge text-bg-success">Nouveau</span>
}
</div>
<h5 class="card-title">{{ f.titre }}</h5>
<p class="card-text small text-secondary">{{ f.description }}</p>
</div>
<ul class="list-group list-group-flush small">
<li class="list-group-item"><i class="bi bi-clock me-2"></i>{{ f.dureeMois }} mois</li>
<li class="list-group-item"><i class="bi bi-award me-2"></i>{{ f.niveau | uppercase }}</li>
</ul>
<div class="card-footer bg-transparent">
@if (f.placesRestantes > 0) {
<span class="text-success fw-semibold">
<i class="bi bi-check-circle me-1"></i>{{ f.placesRestantes }} places restantes
</span>
} @else {
<span class="text-danger fw-semibold"><i class="bi bi-x-circle me-1"></i>Complet</span>
}
</div>
</div>
</div>
} @empty {
<p class="text-center text-secondary">Aucune formation pour le moment.</p>
}
</div>
</div>
</section>
- Q7.6. Placer
<app-liste-formations />entre les chiffres clés et les coordonnées, et compléter lesimportsdeApp. Voici la version finale du composant racine :
// src/app/app.ts (version finale)
import { Component } from '@angular/core';
import { Entete } from './layout/entete/entete';
import { PiedPage } from './layout/pied-page/pied-page';
import { Banniere } from './accueil/banniere/banniere';
import { ChiffresCles } from './accueil/chiffres-cles/chiffres-cles';
import { ListeFormations } from './formations/liste-formations/liste-formations';
import { Contact } from './accueil/contact/contact';
@Component({
imports: [Entete, Banniere, ChiffresCles, ListeFormations, Contact, PiedPage],
selector: 'app-root',
styleUrl: './app.css',
templateUrl: './app.html',
})
export class App {}
<!-- src/app/app.html (version finale) -->
<app-entete />
<main>
<app-banniere />
<app-chiffres-cles />
<app-liste-formations />
<app-contact />
</main>
<app-pied-page />
- Q7.7. (R) Faire les expériences suivantes une par une, noter le résultat, puis revenir au code correct :
- supprimer la propriété
placesRestantesde la quatrième formation : quel message d'erreur obtenez-vous ? Quel est l'intérêt de l'interface ? - remplacer le contenu du tableau par un tableau vide
[]: qu'affiche la page ? Quel bloc est utilisé ? - retirer
UpperCasePipedesimportsdu composant : quel est le code de l'erreur ? Que propose le message ? - passer
placesRestantesde la première formation à0: que devient sa carte ?
- supprimer la propriété
- Q7.8. (R) À quoi sert
track f.iddans le bloc@for? Pourquoi choisit-on l'idplutôt que le titre ? - Q7.9. Ajouter une cinquième formation de votre choix (icône à choisir sur icons.getbootstrap.com). (R) Comment la grille Bootstrap la place-t-elle sur ordinateur ? Le nombre affiché sous le titre a-t-il changé tout seul ?
-
Résultat attendu à la fin de la partie 07
@for: badge « Nouveau » et mention « Complet » affichés grâce à @if, niveau en majuscules grâce au pipe uppercase. Sur téléphone, les cartes s'empilent.Git – fin de la partie 07 :
git add .
git commit -m "Partie 07 : liste des formations avec @for et @if"
git push
-
Partie 08 Tester et vérifier la qualité
- Objectif : exécuter les tests unitaires générés par la CLI, corriger celui qui ne correspond plus à l'application, et vérifier l'affichage sur différents écrans.
- Q8.1. Lancer les tests une seule fois (sans surveillance des fichiers). (R) Combien de fichiers de test et de tests sont exécutés ? Quel test échoue, et pourquoi ? Remarque : avant Angular 21, les projets utilisent Karma, qui ouvre Chrome pour exécuter les tests ; la commande et la démarche restent les mêmes.
ng test --watch=false
# Extrait du résultat
FAIL src/app/app.spec.ts > App > should render title
AssertionError: expected 'Apprenez un métier, construisez votre…' to contain 'Hello, forma-plus'
- Q8.2. Ouvrir
src/app/app.spec.tset remplacer le testshould render titlepar les deux tests ci-dessous. Relancer les tests : ils doivent tous réussir. (R) Que vérifie chacun des deux nouveaux tests ?
it('doit afficher le titre de la bannière', async () => {
const fixture = TestBed.createComponent(App);
await fixture.whenStable();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('h1')?.textContent).toContain('Apprenez un métier');
});
it('doit afficher 4 cartes de formation', async () => {
const fixture = TestBed.createComponent(App);
await fixture.whenStable();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelectorAll('#formations .card').length).toBe(4);
});
- Q8.3. Si vous avez ajouté une cinquième formation en Q7.9, le second test échoue : modifier la valeur attendue pour qu'il réussisse. (R) Un test qui échoue est-il toujours le signe d'une erreur dans l'application ?
- Q8.4. Vérifier l'affichage aux largeurs 390 px (téléphone), 768 px (tablette) et 1280 px (ordinateur) avec la barre d'outils des appareils. (R) Combien de cartes de formation sont affichées par ligne pour chaque largeur ? Quelles classes Bootstrap en sont responsables ?
- Q8.5. Dans Chrome, ouvrir l'onglet Lighthouse des outils de développement et lancer une analyse de la page (mode Navigation, catégories Accessibilité et Bonnes pratiques). (R) Noter les deux scores et une remarque proposée par l'outil.
-
Résultat attendu à la fin de la partie 08
app.spec.ts. Git – fin de la partie 08 :
git add .
git commit -m "Partie 08 : tests unitaires corrigés et complétés"
git push
-
Partie 09 Compiler pour la publication
- Objectif : produire la version de production de l'application, comprendre les avertissements de taille, et tester le résultat comme le verra un visiteur.
- Q9.1. Arrêter
ng serveet compiler l'application. (R) Quels sont les trois fichiers principaux produits et leur taille ? Quelle différence faites-vous entre Raw size et Estimated transfer size?
ng build
# Extrait du résultat
Initial chunk files | Names | Raw size | Estimated transfer size
styles-Y6MBID7J.css | styles | 315.68 kB | 33.18 kB
main-6JJFPLA6.js | main | 214.71 kB | 59.48 kB
scripts-TTWY4XDY.js | scripts | 80.45 kB | 21.60 kB
| Initial total | 610.84 kB | 114.26 kB
▲ [WARNING] bundle initial exceeded maximum budget. Budget 500.00 kB was not met by 110.84 kB
with a total of 610.84 kB.
- Q9.2. (R) L'avertissement indique que l'application dépasse le budget de taille défini dans
angular.json(configurationproduction, sectionbudgets). Quelle partie de l'application pèse le plus lourd ? D'où vient-elle ? Relever le budget à 700 kB pour l'avertissement, garder 1 MB pour l'erreur, puis recompiler.
"budgets": [
{
"type": "initial",
"maximumWarning": "700kB",
"maximumError": "1MB"
},
...
Un budget n'est pas un obstacle à contourner : c'est une alarme qui prévient que l'application devient lourde à télécharger sur un téléphone en 4G. On le relève seulement après avoir vérifié que la taille est justifiée (ici, la feuille de style complète de Bootstrap). Dans un vrai projet, on chercherait aussi à réduire la taille : n'importer que les parties de Bootstrap utilisées, par exemple.
- Q9.3. (R) Ouvrir le dossier
dist/forma-plus/browser/. Quels fichiers contient-il ? Pourquoi leurs noms contiennent-ils une suite de caractères commeY6MBID7J? Que contient le sous-dossiermedia/? - Q9.4. Double-cliquer sur
dist/forma-plus/browser/index.htmlpour l'ouvrir dans le navigateur. (R) La page s'affiche-t-elle ? Ouvrir la console (F12) et expliquer pourquoi. - Q9.5. Servir le dossier avec un vrai serveur web, sans rien installer, grâce à
npx, puis ouvrir l'adresse indiquée. (R) Quel nom de centre et quelle version s'affichent dans le pied de page ? Pourquoi sont-ils différents de ceux deng serve?
npx http-server dist/forma-plus/browser -p 8080
- Q9.6. (R) Exécuter
git status: le dossierdist/apparaît-il ? Dans quel fichier est-il exclu, et pourquoi ne le versionne-t-on pas ? - Q9.7. (R) Si l'application devait être publiée dans un sous-dossier, par exemple
https://www.formaplus.tn/site/, quelle option faudrait-il ajouter àng build? Quelle ligne deindex.htmlserait modifiée ?
-
Résultat attendu à la fin de la partie 09
dist/ avec les valeurs de l'environnement de production.Git – fin de la partie 09 :
git add .
git commit -m "Partie 09 : compilation de production et budgets"
git push
-
Partie 10 Finaliser le dépôt GitHub et version 1.0
- Objectif : rendre le dépôt présentable et marquer la version livrée.
- Q10.1. Compléter le dossier
captures/avec : la page complète sur ordinateur (10_page_ordinateur.png), la page sur téléphone avec le menu ouvert (10_page_telephone.png), le résultat deng test(10_tests.png) et le résultat deng build(10_build.png). - Q10.2. Remplacer le contenu du fichier
README.mdgénéré par Angular par une présentation de votre projet, en suivant le modèle ci-dessous (à gauche). Compléter les versions relevées en Q0.1. - Q10.3. Vérifier que
reponses.mdest complet, et qu'aucun fichier denode_modules/ou dedist/, mot de passe ou jeton n'apparaît dans le dépôt :git ls-files | findstr node_modulessous Windows, ougit ls-files | grep node_modulessous Linux et macOS, ne doit rien afficher. - Q10.4. Faire le dernier commit, puis marquer la version finale avec l'étiquette
v1.0et l'envoyer sur GitHub (commandes à droite). Vérifier que le README s'affiche avec les captures et que l'étiquette apparaît dans Tags.
# FormaPlus
Site vitrine du centre de formation FormaPlus, réalisé
avec Angular et Bootstrap 5 dans le cadre du TP 1 Angular.
## Fonctionnalités
- Page unique découpée en 7 composants
- Liste des formations affichée avec @for et @if
- Environnements de développement et de production
- Affichage adapté aux téléphones (Bootstrap 5)
## Captures d'écran


## Versions utilisées
- Node.js : …
- Angular CLI : …
- Bootstrap : …
## Lancer le projet
npm install
ng serve
## Compiler pour la production
ng build
## Auteur
Prénom Nom – Groupe
git add .
git commit -m "Partie 10 : README, captures et version 1.0"
git push
git tag v1.0
git push origin v1.0
-
Résultat attendu à la fin de la partie 10
v1.0 envoyée sur GitHub, et aucun fichier de node_modules/ versionné.-
Exercices complémentaires (bonus)
- Section « Témoignages » : créer un composant
accueil/temoignagesqui affiche trois avis d'anciens stagiaires (nom, formation suivie, texte) avec@for, dans des cartes ou un carrousel Bootstrap. - Mode sombre : ajouter
data-bs-theme="dark"sur la balise<html>deindex.htmlet observer le résultat. Quels composants faut-il adapter (bannière, sectionsbg-light) ? Le bouton de bascule clair / sombre sera réalisé dans le TP 2, avec la gestion des événements. - Favicon et méta-données : remplacer
public/favicon.icopar une icône personnalisée, et ajouter une balise<meta name="description">dansindex.html. Relancer l'analyse Lighthouse : le score a-t-il changé ? - Publication sur GitHub Pages : publier le site à l'adresse
https://VOTRE-COMPTE.github.io/forma-plus/avec le paquetangular-cli-ghpages(ng add angular-cli-ghpages, puisng deploy --base-href=/forma-plus/). Vérifier d'abord sur la page du paquet qu'il est compatible avec votre version d'Angular. Ajouter le lien du site dans leREADME.md. - Préparer le TP 3 : le template de
ListeFormationsest long. Essayer de déplacer une carte dans un composantCarteFormation: quelle difficulté rencontrez-vous pour lui transmettre la formation à afficher ? Elle sera résolue avec@Input.
-
Compte rendu
- À rendre :
- le lien de votre dépôt GitHub
forma-plus, envoyé dès la partie 01 : c'est ce dépôt qui est corrigé, dans l'état de l'étiquettev1.0; - dans le dépôt, le fichier
reponses.md: réponses aux questions marquées (R), soit Q0.3, Q1.1, Q1.4, Q1.8, Q2.1, Q2.2, Q2.4, Q2.6, Q2.7, Q2.8, Q3.1, Q3.2, Q3.3, Q3.4, Q3.6, Q3.7, Q4.1, Q4.2, Q4.4, Q4.5, la question de l'encadré Git de la partie 04, Q5.1, Q5.3, Q5.6, Q6.3, Q6.5, Q6.7, Q7.2, Q7.7, Q7.8, Q7.9, Q8.1, Q8.2, Q8.3, Q8.4, Q8.5, Q9.1 à Q9.7, ainsi que les questions de réflexion ; - dans le dépôt, le
README.mdet les captures d'écran du dossiercaptures/.
- le lien de votre dépôt GitHub
- Barème indicatif (/20) :
| Critère | Points |
|---|---|
| Partie 00 et 01 – environnement vérifié, projet créé avec la CLI et publié sur GitHub dès le début | 2 |
| Partie 02 – rôle des fichiers, chaîne de démarrage, lecture des messages d'erreur | 2,5 |
Partie 03 – angular.json, port, environnements, configuration de VS Code |
2 |
| Partie 04 – Bootstrap et Bootstrap Icons intégrés avec npm, CSS et JavaScript fonctionnels | 1,5 |
Partie 05 – composant Entete généré, importé et responsive, encapsulation des styles |
2 |
Partie 06 – composants Banniere, Contact (écrit en autonomie) et PiedPage, liaison de propriété |
2,5 |
Partie 07 – interface, @for, @if / @else, @empty, pipe, formations ajoutées |
3 |
| Partie 08 – tests corrigés et réussis, vérification responsive et Lighthouse | 1,5 |
Partie 09 – compilation de production, budgets, test du dossier dist/ |
1,5 |
Git / GitHub – dépôt créé en partie 01, un commit par partie avec un message clair, aucun node_modules/ ni secret versionné, README.md, étiquette v1.0 |
1,5 |
| Total | 20 |
| Bonus | +2 max |
Question de réflexion (à rédiger en 5 lignes) :
Pendant ce TP, vous avez généré chaque composant avec
Pendant ce TP, vous avez généré chaque composant avec
ng generate, puis l'avez importé dans le composant racine. Expliquer ce que la CLI vous a évité de faire à la main, et ce qui se passerait dans un projet de 50 composants si chacun était créé sans elle. Citer une erreur précise rencontrée pendant la séance et la façon dont le message du compilateur vous a aidé à la corriger.