XMS1IE320 - Projet transversal
Master 1 ALMA - Année 2026/2027
30 septembre 2026
Actuellement, les applications qu'on vous présente sont petites
Elles restent rapides à charger
Mais que se passerait-il si jamais on avait une application plus grosse ?
Aujourd'hui, les sites sont de plus en plus lourds
Recharger une page entière = coûteux
Besoin que les sites soient le plus fluide possible à naviguer, et essayer d'économiser des appels serveurs
→ C'est là qu'interviennent les SPA !
Single-Page Application
Page à chargement unique (au lancement du site Web)
Opposé aux MPA (Multi-Page Application)
SPA = plus lourd au démarrage, mais navigation fluide
Les SPA détournent le fonctionnement historique du navigateur
MPA : chargement du HTML à chaque action
SPA : application JS/TS qui intercepte la navigation pour modifier dynamiquement le contenu de la page
Pour une plus grosse application, un framework est préférable
Permet de découper le site en plus petits éléments, d'assurer la navigation... mais aussi de gérer le flux de données reçu par l'application.
Mais surtout... HTML/CSS est statique
JavaScript
Présenté rapidement la dernière fois
TypeScript
Basé sur JavaScript, mais avec des types statiques
Langage de programmation développé par Microsoft
Objectif : améliorer et sécuriser la production de code JavaScript
"Sur-ensemble syntaxique" de JavaScript : tout code JS est compatible avec TS
TypeScript est un langage fortement typé
Code plus lisible
Facilement maintenable
"Protège" mieux contre les erreurs
Offre des options supplémentaires, comme les interfaces
Dans l'onglet "Ressources" des TP
Notez toutefois que ce contenu ne sera pas abordé dans les séances de TP
Framework pour le développement d'applications web
Développé et maintenu par Google, basé sur TypeScript
Spécialisé dans les SPA !
2010 : sortie d'AngularJS
2016 : sortie d'Angular 2, sa réécriture en TypeScript
2 nouvelles versions par an depuis la sortie
Juin 2026 : Angular 22 (version actuelle)
Prévu en juin 2027 : Angular 23
Système de composant (encapsulation du code)
Signals (gestion dynamique des données)
Injection de dépendances
Système de routing
Système de formulaire
Pour utiliser Angular, il faut installer son CLI
DÉFINITION
Un CLI (Command Line Interface) est un outil en ligne de commande qui permet d'interagir avec un logiciel ou un framework, en exécutant des commandes spécifiques pour effectuer des tâches telles que la création de projets, la génération de composants, la gestion des dépendances, etc.
npm install -g @angular/cli
Après avoir installé le CLI, vous pouvez créer un nouveau projet Angular :
ng new nom-projet
DÉFINITION
Un composant est une brique d'interface qui regroupe une partie de la présentation et la logique nécessaire à son fonctionnement
Un composant est constitué de 3 éléments :
Pour générer un nouveau composant, tapez la commande suivante dans un terminal :
Version courte
ng g c nom-composant
Version longue
ng generate component nom-composant
@Component({
selector: 'app-example',
imports: [],
templateUrl: './example.html', // Possible de mettre un template brut
styleUrl: './example.css', // Possible de mettre un style brut
})
Le sélecteur est le nom de la balise HTML utilisée pour insérer le composant dans le template.
Prenez l'exemple suivant :
@Component({
selector: 'app-product'
})
Cette balise peut être utilisée dans le template pour insérer le composant :
import { Component } from '@angular/core';
import { Card } from 'chemin/vers/mon/composant/card'; // Import ici
@Component({
selector: 'app-tp1',
imports: [Card], // Attention à bien l'importer ici aussi !
templateUrl: './tp1.html',
styleUrl: './tp1.css',
})
export class Tp1 {
// Mon code TypeScript
}
Une application Angular est un arbre de composants
Notez ici que d'autres éléments peuvent s'ajouter à notre app
Prenons ce composant TypeScript en exemple :
export class Product {
name = 'Clavier';
price = 79.99;
buy() {
console.log('Produit acheté');
}
}
Permet d'afficher la valeur d'une variable dynamiquement
Mettre le nom de la variable entre {{ }}
{{ name }}
{{ price }} €
Permet de définir des valeurs pour des propriétés d'éléments HTML, de composants Angular, ...
Cela permet notamment de :
On met la property entre []
String interpolation : afficher une valeur dans le HTML
Property binding : modifier la propriété d'un élément ou d'un composant
Permet d'ajouter des événements à des composants Angular
On met l'event entre ()
Et si... on combinait les 2 ?
Permet d'à la fois de lier une valeur dans un élément tout en donnant la possibilité de propager des changements
Ici, affiche les données du champ, en plus d'affecter un événement au changement
Le template que vous affichez peut dépendre de l'état du composant
@if (isLogged) {
Bienvenue !
} @else {
Veuillez vous connecter.
}
Vous pouvez parfois avoir plusieurs objets identiques à afficher sur votre page
@for (product of products; track product.id) {
}
Inspiré du switch en JavaScript
@switch (condition) {
@case (caseA) {
Je réalise le cas A !
}
@case (caseB)
@case (caseC) {
Je réalise le cas B... ou peut-être le C ?
}
@default {
Je suis le cas exécuté par défaut !
}
}
@defer : utilisé pour faire un chargement différé d'un composant (lazy load)
@boundary & @error : équivalent de l'instruction try catch
@let : créer une variable locale
Si vous avez besoin d'afficher du contenu personnalisé pour un élément "générique"
Dans votre composant :
[...]
[...]
Dans votre code :
Angular propose plusieurs façons de créer et gérer des formulaires :
Les formulaires réactifs sont des formulaires plus robustes, réutilisables et faciles à tester.
Ils sont généralement utilisés pour des formulaires complexes ou lorsque vous avez besoin d'une logique de validation avancée.
Exemple : un formulaire complexe avec plusieurs champs et validations.
Les formulaires basés sur les modèles sont plus simples à mettre en place et conviennent bien aux formulaires simples.
Exemple : une barre de recherche, un champ de saisie, etc...
C'est ce qu'on va utiliser en TP !
Changement dynamique de nom de variable
Côté TypeScript
import { Component, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
@Component({
imports: [FormsModule],
selector: 'app-product',
styleUrl: './product.css',
templateUrl: './product.html',
})
export class Product {
productName = signal('');
}
Côté HTML
{{ productName() }}
Montré juste avant dans le code
Enveloppe une valeur, et envoie une notification aux consommateurs intéressés lorsque cette valeur change.
Mais comment je gère les données dans mon application ?
Possibilité n°1 : tout mettre dans le fichier TypeScript
Avantages
Plus simple à implémenter (?)
Inconvénients
Pas de séparation de responsabilité
Tout le code est concentré au même endroit
Pas réutilisable
Possibilité n°2
DÉFINITION
Un service est un bout de code réutilisable dans l'ensemble d'une application Angular qui permet de gérer la logique métier, la récupération des données et d'autres fonctions
Pour générer un nouveau service, tapez la commande suivante dans un terminal :
Version courte
ng g s nom-service
Version longue
ng generate service nom-service
import { Service } from '@angular/core';
@Service()
export class Auth {}
Comment faire pour les structurer ?
DÉFINITION
Les interfaces en TypeScript permettent de définir des contrats au sein de votre code ainsi que de définir des formes personnalisées pour des types de données complexes.
Basiquement identique à la POO
Pour générer une nouvelle interface, tapez la commande suivante dans un terminal :
Version courte
ng g i nom-interface
Version longue
ng generate interface nom-interface
interface Personne {
nom: string;
age: number;
sePresenter(): void;
}
class Employe implements Personne {
nom: string;
age: number;
constructor(nom: string, age: number) {
this.nom = nom;
this.age = age;
}
sePresenter() {
console.log(`Je m'appelle ${this.nom} et j'ai ${this.age} ans.`);
}
}
@Service()
export class ProductsService {
// Donnée factice (stub)
Employe product = new Employe {
nom = "Quentin",
age = 22
}
// Appel HTTP (voir CM4)
private http = inject(HttpClient);
getEmploye(id: string): Observable {
return this.http.get(`/api/employe/${nom}`);
}
}
Mais je veux que mon site ait plusieurs pages...
DÉFINITION
Une route est un chemin d'accès à une page ou à une vue spécifique dans une application Angular
Pour créer une nouvelle route, il faut modifier le fichier app.routes.ts :
export const routes: Routes = [
{
path: 'accueil',
component: Accueil
},
{
path: 'produits',
component: Produits
}
];
Un moyen de rediriger les utilisateurs vers une autre page
export const routes: Routes = [
{
path: 'accueil',
component: Accueil
},
{
path: 'produits',
component: Produits
},
{
path: '**',
redirectTo: 'accueil'
}
];
Il est également possible de faire des redirections conditionnelles.
Vous pouvez passer des paramètres dans votre route pour personnaliser le contenu affiché
// [...]
{
path: 'produits',
component: Produits
}
{
path: 'produit/:id',
component: Produit
},
{
path: '**',
redirectTo: 'accueil'
}
];
http://localhost:4200/produit/1 est une URL valide
C'est le composant qui vous permet de gérer l'ensemble de votre routing.
Il sert de "placeholder", et Angular le remplie dynamiquement en fonction de la valeur de la route
C'est impossible ?
C'est normal !
DÉFINITION
Un guard est une fonctionnalité d'Angular qui permet de contrôler l'accès à des routes spécifiques dans votre application
Pour générer un nouveau guard, tapez la commande suivante dans un terminal :
Version courte
ng g g nom-guard
Version longue
ng generate guard nom-guard
Détermine si un utilisateur peut utiliser la route
Utilisé généralement par défaut quand vous voulez faire fonctionner un guard
Détermine si un utilisateur peut accéder aux routes enfant d'une route parent
Utile quand vous voulez protéger une section entière de routes
Détermine si un utilisateur peut quitter une route
Utile si vous voulez éviter que quelqu'un quitte votre page si votre formulaire n'est pas sauvegardé
Réalise un contrôle, et détermine si un utilisateur peut accéder à une route
Utile si vous voulez faire du routing conditionnel, du A/B testing, ...
Par exemple, vous voulez faire en sorte qu'un admin ait accès à un panel, mais les utilisateurs par défaut soient redirigés vers une autre page.
Exemple du site de TP
import { inject } from "@angular/core";
import { CanActivateFn, Router } from '@angular/router';
export const accesTpGuard: CanActivateFn = () => {
const router = inject(Router); // Injection de dépendances
router.navigate(['/']);
return false;
};
Exemple simple : interdiction d'accès à une page
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from '../services/auth.service';
export const authGuard: CanActivateFn = (route, state) => {
// Injections de dépendances
const authService = inject(AuthService);
const router = inject(Router);
if (authService.getAuthenticated()) {
return true;
} else {
router.navigate(['/login']);
return false;
}
};
Guard d'accès après authentification
export const routes: Routes = [
{
path: 'accueil',
component: Accueil
},
{
path: 'produits',
component: Produits,
canActivate: [AuthGuard]
},
[...]
];
Mais comment faire en sorte de partager de la donnée entre mes composants ?
Le plus simple des deux
Parent : utilise le property binding
Enfant : utilise l'intruction @Input
import { Input } from '@angular/core';
export class UserCardComponent {
@Input() user: any;
}
Enfant : utilise l'intruction @Output
import { Output, EventEmitter } from '@angular/core';
export class UserCardComponent {
@Output()
deleteUser = new EventEmitter();
onDelete() {
this.deleteUser.emit();
}
}
Parent : événement au moment de la réception
removeUser() {
console.log('Utilisateur supprimé');
}