This commit is contained in:
Johan
2025-12-17 09:50:36 +01:00
parent 69f2bea0e7
commit 00b5355861
2 changed files with 57 additions and 53 deletions

View File

@@ -5,25 +5,28 @@
<input
type="text"
placeholder="Ajouter une nouvelle tâche..."
[formControl]="newTodoTitle"
(keydown.enter)="addTodo()"
/>
<button>Ajouter</button>
<button (click)="addTodo()" [disabled]="newTodoTitle.invalid">Ajouter</button>
</div>
</header>
<ul class="todo-list">
<li>
<span class="todo-title">
Tâche d'exemple
</span>
<button class="btn-remove">X</button>
</li>
</ul>
<footer>
<span>X tâche(s) restante(s)</span>
</footer>
<p class="empty-state">Bravo, aucune tâche pour le moment !</p>
@if (todos().length > 0) {
<ul class="todo-list">
@for (todo of todos(); track todo.id) {
<li [class.completed]="todo.completed">
<span (click)="toggleTodo(todo.id)" class="todo-title">
{{ todo.title }}
</span>
<button (click)="removeTodo(todo.id)" class="btn-remove">X</button>
</li>
}
</ul>
<footer>
<span>{{ remainingTodos() }} tâche(s) restante(s)</span>
</footer>
} @else {
<p class="empty-state">Bravo, aucune tâche pour le moment !</p>
}
</div>

View File

@@ -7,61 +7,62 @@ import { Todo } from '../../../core/models/todo.model';
templateUrl: './todo-list.component.html',
styleUrls: ['./todo-list.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ReactiveFormsModule],
imports: [ReactiveFormsModule], // Importer ReactiveFormsModule pour utiliser FormControl
})
export class TodoListComponent {
// --- ÉTAT (State) ---
// TODO 1.1: Créer un signal pour stocker la liste des tâches.
// Utilisez `signal<Todo[]>()` et initialisez-le avec le tableau ci-dessous.
/*
[
{ id: 1, title: 'Apprendre les bases d\'Angular', completed: true },
{ id: 2, title: 'Comprendre les signals', completed: false },
{ id: 3, title: 'Créer un premier composant', completed: false },
]
*/
readonly todos = signal<Todo[]>([]); // <- REMPLACER [] par le tableau ci-dessus
// Le signal `todos` est la source de vérité pour notre liste de tâches.
// On utilise `signal<Type>(valeurInitiale)` pour le créer.
readonly todos = signal<Todo[]>([
{ id: 1, title: 'Apprendre les bases d\'Angular', completed: true },
{ id: 2, title: 'Comprendre les signals', completed: false },
{ id: 3, title: 'Créer un premier composant', completed: false },
]);
// Un signal `computed` dérive sa valeur d'autres signaux.
// Il se met à jour automatiquement quand `todos` change.
readonly remainingTodos = computed(() => this.todos().filter(t => !t.completed).length);
// TODO 1.2: Créer un signal "computed" pour calculer le nombre de tâches restantes.
// Utilisez `computed(() => ...)` et filtrez le signal `todos` pour ne compter
// que les tâches où `completed` est `false`.
readonly remainingTodos = computed(() => 0); // <- REMPLACER 0 par le calcul
// TODO 1.3: Créer un FormControl pour le champ de saisie d'une nouvelle tâche.
// Utilisez `new FormControl()` avec une chaîne vide comme valeur initiale.
// Dans les options, ajoutez `nonNullable: true` et des validateurs :
// `Validators.required` et `Validators.minLength(3)`.
readonly newTodoTitle = new FormControl(''); // <- AJOUTER les options
// Utilisation d'un FormControl pour gérer l'input de manière réactive.
readonly newTodoTitle = new FormControl('', {
nonNullable: true,
validators: [Validators.required, Validators.minLength(3)],
});
// --- ACTIONS ---
/** Ajoute une nouvelle tâche à la liste. */
addTodo(): void {
// TODO 1.4: Implémenter la logique d'ajout.
// 1. Vérifiez si `this.newTodoTitle` est invalide. Si c'est le cas, arrêtez la fonction avec `return;`.
// 2. Créez un objet `newTodo` de type `Todo` avec un `id` unique (Date.now()),
// le titre provenant de `this.newTodoTitle.value`, et `completed: false`.
// 3. Mettez à jour le signal `todos` avec `this.todos.update(currentTodos => [...currentTodos, newTodo])`.
// 4. Réinitialisez le champ de saisie avec `this.newTodoTitle.reset()`.
if (this.newTodoTitle.invalid) {
return; // Ne rien faire si l'input est invalide
}
const newTodo: Todo = {
id: Date.now(), // Utilisation d'un timestamp pour un ID unique simple
title: this.newTodoTitle.value,
completed: false,
};
// `update` permet de modifier la valeur du signal en se basant sur la valeur actuelle.
// C'est une bonne pratique de créer un nouveau tableau (immuabilité).
this.todos.update(currentTodos => [...currentTodos, newTodo]);
this.newTodoTitle.reset(); // Vider le champ de saisie
}
/** Supprime une tâche de la liste. */
removeTodo(id: number): void {
// TODO 1.5: Implémenter la logique de suppression.
// Utilisez `this.todos.update(currentTodos => ...)` et la méthode `.filter()`
// pour retourner un nouveau tableau sans la tâche correspondant à l'`id`.
this.todos.update(currentTodos => currentTodos.filter(todo => todo.id !== id));
}
/** Bascule l'état "complété" d'une tâche. */
toggleTodo(id: number): void {
// TODO 1.6: Implémenter la logique de bascule.
// Utilisez `this.todos.update(currentTodos => ...)` et la méthode `.map()`.
// Pour chaque `todo` dans le tableau, si son `id` correspond, retournez un nouvel objet
// avec la propriété `completed` inversée (`!todo.completed`). Sinon, retournez le `todo` original.
this.todos.update(currentTodos =>
currentTodos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)
);
}
}