Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/app/app.component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* Styles du composant racine */
nav {
display: flex;
gap: 1rem;
margin-bottom: 1rem;
}
12 changes: 12 additions & 0 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!-- Barre de navigation simple pour accéder aux pages principales -->
<nav>
<a routerLink="/">Accueil</a>
<a routerLink="/users/all">Liste des utilisateurs</a>
<a routerLink="/users/create">Créer un utilisateur</a>
</nav>

<!--
router-outlet est une zone d'affichage dynamique.
Angular y rend le composant correspondant à la route active.
-->
<router-outlet></router-outlet>
31 changes: 31 additions & 0 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Component, OnInit } from '@angular/core';
import { RouterLink, RouterOutlet } from '@angular/router';

/**
* @Component transforme la classe TypeScript en composant Angular.
* selector:
* - nom de la balise HTML personnalisée utilisée dans index.html (<app-root>).
* templateUrl:
* - chemin vers le fichier HTML du composant (vue).
* styleUrls:
* - liste de fichiers CSS appliqués uniquement à ce composant (encapsulation).
* standalone:
* - indique que le composant peut être démarré sans NgModule racine.
*/
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet, RouterLink],
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
/**
* ngOnInit est un hook du cycle de vie Angular.
* Il est appelé une fois, juste après la création du composant.
* C'est l'endroit recommandé pour lancer les initialisations simples.
*/
ngOnInit(): void {
// Aucune initialisation spécifique pour le moment.
}
}
45 changes: 45 additions & 0 deletions src/app/users/crud/crud.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Component, OnInit } from '@angular/core';
import { UsersService } from '../services/users.service';
import { User } from '../model/user.model';

/**
* Composant de liste CRUD.
* @Component configure:
* - selector: balise utilisable dans d'autres templates.
* - template: vue HTML inline de ce composant.
*/
@Component({
selector: 'app-crud',
template: `
<h2>Liste des utilisateurs</h2>
<app-user-card *ngFor="let user of userList" [user]="user"></app-user-card>
`,
})
export class CrudComponent implements OnInit {
/** Tableau alimenté avec les données de l'API */
userList: User[] = [];

/**
* Injection de dépendances:
* Angular fournit automatiquement une instance de UsersService.
*/
constructor(private usersService: UsersService) {}

/**
* Hook de cycle de vie exécuté après la création du composant.
* On y déclenche l'initialisation métier (chargement de la liste).
*/
ngOnInit(): void {
this.loadUsers();
}

/**
* Récupère les utilisateurs via le service.
* subscribe(...) consomme l'Observable et met à jour l'état local.
*/
private loadUsers(): void {
this.usersService.getUsers().subscribe((users) => {
this.userList = users;
});
}
}
15 changes: 15 additions & 0 deletions src/app/users/model/user.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Interface décrivant la forme d'un utilisateur.
* Une interface TypeScript permet de typer les données manipulées
* pour éviter des erreurs et faciliter l'autocomplétion.
*/
export interface User {
/** Identifiant unique de l'utilisateur côté API/base de données */
id: number;
/** Prénom affiché dans l'interface */
firstName: string;
/** Nom de famille affiché dans l'interface */
lastName: string;
/** Adresse e-mail utilisée pour contacter ou rechercher l'utilisateur */
email: string;
}
56 changes: 56 additions & 0 deletions src/app/users/services/users.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { User } from '../model/user.model';

/**
* URL de base de l'API REST des utilisateurs.
* Toutes les opérations CRUD partent de cette route.
*/
const baseUrl = 'http://localhost:8081/api/v1/employees';

/**
* @Injectable permet à Angular d'instancier ce service via l'injection
* de dépendances. providedIn: 'root' signifie "singleton global".
*/
@Injectable({
providedIn: 'root',
})
export class UsersService {
/**
* HttpClient est injecté automatiquement par Angular.
* Il sert à faire les requêtes HTTP (GET, POST, PUT, DELETE).
*/
constructor(private http: HttpClient) {}

/**
* Lit tous les utilisateurs.
* Retourne un Observable<User[]>:
* - un Observable représente un flux asynchrone de données.
* - le composant s'abonne (subscribe) pour recevoir la réponse.
*/
getUsers(): Observable<User[]> {
return this.http.get<User[]>(baseUrl);
}

/** Crée un nouvel utilisateur côté API. */
create(data: Partial<User>): Observable<User> {
return this.http.post<User>(baseUrl, data);
}

/** Met à jour un utilisateur existant via son id. */
update(id: number, data: Partial<User>): Observable<User> {
return this.http.put<User>(`${baseUrl}/${id}`, data);
}

/** Supprime un utilisateur via son id. */
delete(id: number): Observable<void> {
return this.http.delete<void>(`${baseUrl}/${id}`);
}

/** Recherche des utilisateurs par adresse e-mail. */
findByEmail(email: string): Observable<User[]> {
const params = new HttpParams().set('email', email);
return this.http.get<User[]>(baseUrl, { params });
}
}
24 changes: 24 additions & 0 deletions src/app/users/user-card/user-card.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Component, Input } from '@angular/core';
import { User } from '../model/user.model';

/**
* Composant enfant chargé d'afficher un utilisateur.
*/
@Component({
selector: 'app-user-card',
template: `
<article>
<h3>{{ user.firstName }} {{ user.lastName }}</h3>
<p>{{ user.email }}</p>
</article>
`,
})
export class UserCardComponent {
/**
* @Input() reçoit des données depuis le composant parent.
* Exemple:
* <app-user-card [user]="user"></app-user-card>
* Le parent passe l'objet user au composant enfant.
*/
@Input() user!: User;
}
20 changes: 20 additions & 0 deletions src/app/users/users-routing.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CrudComponent } from './crud/crud.component';

/**
* Configuration des routes internes au module users.
* - 'all' affiche la liste des utilisateurs.
* - 'create' pourrait afficher un formulaire de création
* (ici, on réutilise CrudComponent pour garder l'exemple simple).
*/
const routes: Routes = [
{ path: 'all', component: CrudComponent },
{ path: 'create', component: CrudComponent },
];

@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class UsersRoutingModule {}
22 changes: 22 additions & 0 deletions src/app/users/users.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { UsersRoutingModule } from './users-routing.module';
import { CrudComponent } from './crud/crud.component';
import { UserCardComponent } from './user-card/user-card.component';

/**
* @NgModule regroupe les éléments liés à une fonctionnalité.
* imports:
* - modules dont ce module a besoin (directives Angular, HTTP, routing local).
* declarations:
* - composants appartenant à ce module.
* providers:
* - services créés pour ce module (vide ici car UsersService est fourni en root).
*/
@NgModule({
imports: [CommonModule, HttpClientModule, UsersRoutingModule],
declarations: [CrudComponent, UserCardComponent],
providers: [],
})
export class UsersModule {}
17 changes: 17 additions & 0 deletions src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<title>Formation Angular</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<!--
Fichier HTML racine livré par le navigateur.
Angular y injecte l'application dans la balise <app-root>.
Cette balise correspond au selector du composant racine.
-->
<app-root></app-root>
</body>
</html>
31 changes: 31 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter, Routes } from '@angular/router';
import { AppComponent } from './app/app.component';

/**
* Routes principales de l'application.
* - '' affiche la page racine (AppComponent).
* - 'users' charge le module utilisateurs de façon paresseuse (lazy loading)
* pour éviter de charger tout le code dès le démarrage.
*/
const routes: Routes = [
{ path: '', component: AppComponent },
{
path: 'users',
loadChildren: () =>
import('./app/users/users.module').then((m) => m.UsersModule),
},
];

/**
* Point d'entrée de l'application Angular.
* bootstrapApplication:
* - démarre l'application avec un composant racine standalone.
* providers:
* - enregistre des services globaux de l'application.
* provideRouter(routes):
* - active la navigation Angular et injecte la configuration des routes.
*/
bootstrapApplication(AppComponent, {
providers: [provideRouter(routes)],
}).catch((err) => console.error(err));