Nous allons développer une petite application permettant d’enregistrer des signalements. Il est préférable d’avoir un niveau intermédiaire en Angular et NestJs.
Le fonctionnement sera le suivant :
- L’utilisateur saisit un signalement dans Angular.
- Si Internet fonctionne, le signalement est envoyé à NestJS.
- Si Internet est coupé, le signalement est conservé dans
localStorage. - Lorsque la connexion revient, Angular envoie automatiquement le signalement à NestJS.
- NestJS enregistre les informations dans MySQL.
Création de ‘entité MySQL
Dans notre projet NestJS, nous allons créer le fichier signalement.entity.ts.
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn
} from 'typeorm';
@Entity('signalements')
export class Signalement {
@PrimaryGeneratedColumn()
id: number;
// Contenu du signalement
@Column('text')
contenu: string;
// Date de création automatique
@CreateDateColumn()
dateCreation: Date;
}
Assurez-vous que votre projet NestJS est connecté à MySQL et que l’entité est enregistrée dans TypeORM.
Pour cet exercice, nous allons utiliser synchronize: true en développement afin de créer la table automatiquement. A n’est pas utilise en production.
Création du service NestJS
Fichier signalements.service.ts :
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Signalement } from './signalement.entity';
@Injectable()
export class SignalementsService {
constructor(
@InjectRepository(Signalement)
private readonly repository: Repository<Signalement>
) {}
// Enregistrer un nouveau signalement
async creer(contenu: string) {
// Création de l'objet
const signalement = this.repository.create({
contenu
});
// Enregistrement dans MySQL
return this.repository.save(signalement);
}
}
Dans signalements.controller.ts :
import {
Controller,
Post,
Body
} from '@nestjs/common';
import { SignalementsService } from './signalements.service';
@Controller('signalements')
export class SignalementsController {
constructor(
private readonly service: SignalementsService
) {}
@Post()
creer(@Body('contenu') contenu: string) {
// Transmettre le contenu au service
return this.service.creer(contenu);
}
}
Pour que notre route fonctionne, nous allons déclarer le contrôleur, le service et TypeOrmModule.forFeature([Signalement]) dans notre module NestJS. Et activer également CORS pour l’application Angular.
Test avec Postman
Méthode : POST
Adresse :
http://localhost:3000/signalements
Body → raw → JSON :
{
"contenu": "Une panne informatique a été constatée."
}
Résultat attendu :
{
"id": 1,
"contenu": "Une panne informatique a été constatée.",
"dateCreation": "2026-10-10T08:00:00.000Z"
}
Angular : détecter la connexion Internet
Nous allons utiliser deux Signals :
readonly enLigne = signal(navigator.onLine);
readonly enAttente = signal(
localStorage.getItem('signalement') ?? ''
);
Le premier indique l’état de la connexion. Le deuxième contient le signalement qui attend une synchronisation.
Dans le composant app.ts :
import {
Component,
HostListener,
inject,
signal
} from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-root',
standalone: true,
templateUrl: './app.html'
})
export class App {
private readonly http = inject(HttpClient);
private readonly apiUrl =
'http://localhost:3000/signalements';
// État de la connexion Internet
readonly enLigne = signal(navigator.onLine);
// Signalement conservé localement
readonly enAttente = signal(
localStorage.getItem('signalement') ?? ''
);
// Évite plusieurs envois simultanés
readonly sauvegardeEnCours = signal(false);
constructor() {
// Synchroniser les données au démarrage
this.synchroniser();
}
// Détection du retour d'Internet
@HostListener('window:online')
retourInternet() {
this.enLigne.set(true);
// Envoyer les données en attente
this.synchroniser();
}
// Détection de la coupure Internet
@HostListener('window:offline')
perteInternet() {
this.enLigne.set(false);
}
// Enregistrement du signalement
enregistrer(contenu: string) {
const texte = contenu.trim();
if (!texte || this.enAttente()) {
return;
}
// Sauvegarde locale avant tout envoi
localStorage.setItem('signalement', texte);
this.enAttente.set(texte);
// Tentative d'envoi vers NestJS
this.synchroniser();
}
// Synchronisation avec le serveur
synchroniser() {
if (
!this.enLigne() ||
!this.enAttente() ||
this.sauvegardeEnCours()
) {
return;
}
this.sauvegardeEnCours.set(true);
this.http.post(this.apiUrl, {
contenu: this.enAttente()
}).subscribe({
next: () => {
// Supprimer uniquement après succès
localStorage.removeItem('signalement');
this.enAttente.set('');
this.sauvegardeEnCours.set(false);
},
error: (erreur) => {
console.error('Erreur de synchronisation', erreur);
// Les données restent dans localStorage
this.sauvegardeEnCours.set(false);
}
});
}
}
Point important : navigator.onLine indique si le navigateur est connecté à un réseau. Il ne garantit pas que le serveur NestJS est accessible. C’est pourquoi nous conservons le signalement lorsqu’une requête HTTP échoue.
Cette première version gère un seul signalement en attente. Pour gérer plusieurs signalements, il faudra ensuite utiliser un tableau ou une file d’attente.
Création de l’interface HTML
<h2>Gestion des signalements</h2>
<!-- Message affiché hors connexion -->
@if (!enLigne()) {
<p style="color: red;">
⚠️ Connexion Internet indisponible
</p>
}
<!-- Formulaire -->
<textarea
#contenu
placeholder="Décrivez votre signalement">
</textarea>
<br><br>
<button
[disabled]="!!enAttente() || sauvegardeEnCours()"
(click)="enregistrer(contenu.value); contenu.value = ''">
Enregistrer
</button>
<!-- Information sur la synchronisation -->
@if (enAttente()) {
<p>
Signalement en attente de synchronisation.
</p>
<p>{{ enAttente() }}</p>
}
@if (sauvegardeEnCours()) {
<p>Synchronisation en cours...</p>
}
Transformation d’Angular en PWA
Dans notre projet Angular, il faut exécute :
ng add @angular/pwa
Cette commande ajoute notamment un service worker et un manifeste permettant de rendre l’application installable.
A retenir
Nous avons travaillé la communication entre Angular et NestJS, l’utilisation des Signals, le stockage local, la détection des changements de connexion et l’enregistrement des données avec TypeORM et MySQL.
Vous pouvez télécharger le code source de l’exemple avec un design amélioré.