commit 69f2bea0e7790c41a19ba187fb80334cd8d143a6 Author: Johan Date: Wed Dec 17 09:49:48 2025 +0100 first comit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f166060 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.ts] +quote_type = single +ij_typescript_use_double_quotes = false + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b1d225e --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files. + +# Compiled output +/dist +/tmp +/out-tsc +/bazel-out + +# Node +/node_modules +npm-debug.log +yarn-error.log + +# IDEs and editors +.idea/ +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# Visual Studio Code +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# Miscellaneous +/.angular/cache +.sass-cache/ +/connect.lock +/coverage +/libpeerconnection.log +testem.log +/typings +__screenshots__/ + +# System files +.DS_Store +Thumbs.db diff --git a/README.md b/README.md new file mode 100644 index 0000000..7845e25 --- /dev/null +++ b/README.md @@ -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"] + 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([...])`. + * 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 `` à 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 `