TP done
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user