first comit

This commit is contained in:
Johan
2025-12-17 09:49:48 +01:00
commit 69f2bea0e7
23 changed files with 10487 additions and 0 deletions

149
README.md Normal file
View File

@@ -0,0 +1,149 @@
# Démonstration 1 : Todo List (Hello, Signals!) - Gestion d'une Todo-List locale
Bienvenue dans cette première démonstration pratique d'Angular !
L'objectif est de construire une application de type "Todo List" simple et entièrement fonctionnelle.
Toutes les données et la logique seront contenues dans un seul composant,
ce qui nous permettra de nous concentrer sur les concepts fondamentaux d'Angular moderne.
---
### Objectifs Pédagogiques
À la fin de cette démonstration, vous saurez :
* **Créer un état réactif** avec `signal()` pour stocker les données de votre application.
* **Dériver un état** à partir d'un autre avec `computed()` pour des calculs automatiques.
* **Gérer les entrées utilisateur** de manière robuste avec `FormControl`.
* **Mettre à jour l'état** de manière immuable en utilisant la méthode `.update()` des signaux.
* **Afficher dynamiquement des données** dans un template en utilisant la nouvelle syntaxe `@if` et `@for`.
* **Lier des événements** du template (comme un clic) à des méthodes dans votre composant.
Voici un aperçu de la circulation des données que vous allez construire :
```mermaid
graph TD
subgraph "État (Signals)"
A["todos = signal<Todo[]>"]
B[remainingTodos = computed]
end
subgraph "Formulaire"
C[newTodoTitle = FormControl]
end
subgraph "Actions (Méthodes)"
E[addTodo]
F[removeTodo]
G[toggleTodo]
end
subgraph "Vue (Template HTML)"
D[Affichage & Événements]
end
%% Dépendances de données
A -- "dérive de" --> B
A -- "lu par" --> D
B -- "lu par" --> D
C -- "lu par" --> D
%% Flux d'actions
D -- "clic / keydown" --> E
D -- "clic" --> F
D -- "clic" --> G
D -- "saisie" --> C
E -- "appelle todos.update()" --> A
F -- "appelle todos.update()" --> A
G -- "appelle todos.update()" --> A
E -- "appelle .reset()" --> C
```
-----
### Installation
1. Ouvrir le projet sous WebStorm.
2. Ouvrir un terminal dans WebStorm.
3. Lancer la commande `npm install` pour installer les dépendances.
4. Lancer la commande `ng serve` pour démarrer le serveur de développement.
5. Ouvrir le navigateur à l'adresse `http://localhost:4200/`.
---
### Instructions
Le projet est volontairement déjà configuré.
Votre mission est de compléter le code dans les fichiers `todo-list.component.ts` et `todo-list.component.html` en suivant les indications `// TODO`.
Vous travaillerez sur deux fichiers qui interagissent comme suit :
```mermaid
graph LR
subgraph "Logique (Étape 1)"
TS[todo-list.component.ts]
end
subgraph "Vue (Étape 2)"
HTML[todo-list.component.html]
end
TS -- "expose les données (signals, formControl)" --> HTML
HTML -- "déclenche les méthodes (click), (keydown.enter)" --> TS
```
#### Étape 1 : la logique du composant (`todo-list.component.ts`)
Ouvrez le fichier `app/features/todo/todo-list/todo-list.component.ts`.
Nous allons d'abord définir l'état et les actions de notre composant.
1. **`// TODO 1.1` : Créer le signal d'état principal.**
* Déclarez une propriété `readonly todos` et initialisez-la avec `signal<Todo[]>([...])`.
* Utilisez le tableau de tâches fourni dans les commentaires pour avoir des données de départ.
2. **`// TODO 1.2` : Créer un signal dérivé (computed).**
* Déclarez une propriété `readonly remainingTodos` et utilisez la fonction `computed()` pour calculer automatiquement le nombre de tâches non complétées à partir du signal `todos`.
3. **`// TODO 1.3` : Créer le contrôle de formulaire.**
* Déclarez une propriété `readonly newTodoTitle` et initialisez-la avec un `new FormControl()`.
* Assurez-vous qu'il ne peut pas être nul (`nonNullable: true`) et ajoutez des validateurs pour qu'il soit requis (`Validators.required`) et ait une longueur minimale (`Validators.minLength(3)`).
4. **`// TODO 1.4` : Implémenter la méthode `addTodo()`.**
* À l'intérieur de la méthode, vérifiez d'abord si `newTodoTitle` est valide.
* Créez un nouvel objet `Todo`.
* Utilisez `this.todos.update(...)` pour ajouter la nouvelle tâche à la liste existante.
* Réinitialisez le champ de saisie avec `.reset()`.
5. **`// TODO 1.5` : Implémenter la méthode `removeTodo()`.**
* Utilisez `this.todos.update(...)` et la méthode `.filter()` des tableaux pour retourner une nouvelle liste sans la tâche à supprimer.
6. **`// TODO 1.6` : Implémenter la méthode `toggleTodo()`.**
* Utilisez `this.todos.update(...)` et la méthode `.map()` des tableaux pour créer une nouvelle liste où l'état `completed` de la tâche ciblée est inversé.
#### Étape 2 : l'affichage et les interactions (`todo-list.component.html`)
Ouvrez le fichier `app/features/todo/todo-list/todo-list.component.html`.
Maintenant que la logique est prête, connectons-la à notre vue.
1. **`// TODO 2.1` : Connecter le champ de saisie.**
* Liez l'input au `FormControl` que vous avez créé en utilisant la liaison de propriété `[formControl]`.
* Ajoutez un événement `(keydown.enter)` pour appeler la méthode `addTodo()` lorsque l'utilisateur appuie sur "Entrée".
2. **`// TODO 2.2` : Connecter le bouton "Ajouter".**
* Liez l'événement `(click)` du bouton à la méthode `addTodo()`.
* Désactivez le bouton si le formulaire est invalide en utilisant `[disabled]`.
3. **`// TODO 2.3` : Afficher la liste des tâches.**
* Utilisez un bloc `@if` pour vérifier si la liste `todos()` contient des éléments.
* À l'intérieur, utilisez une boucle `@for` pour itérer sur `todos()`. N'oubliez pas le `track todo.id` pour les performances !
* Affichez le titre de la tâche en utilisant l'interpolation `{{ ... }}`.
* Appliquez la classe `.completed` dynamiquement avec `[class.completed]`.
4. **`// TODO 2.4` : Ajouter les actions sur chaque tâche.**
* Dans la boucle `@for`, liez l'événement `(click)` du `<span>` à la méthode `toggleTodo(todo.id)`.
* Liez l'événement `(click)` du bouton de suppression à la méthode `removeTodo(todo.id)`.
5. **`// TODO 2.5` : Afficher le compteur de tâches restantes.**
* Dans le `<footer>`, affichez la valeur du signal `remainingTodos()` en utilisant l'interpolation. N'oubliez pas les parenthèses `()` pour lire la valeur d'un signal !
Une fois toutes les étapes terminées, votre application devrait être entièrement fonctionnelle !