Module JS.11 – Mini-projet
Objectif
Créer une application interactive JavaScript complète pour valider toutes les compétences JavaScript acquises.
Théorie
Application : Gestionnaire de tâches web
Application complète utilisant toutes les fonctionnalités JavaScript apprises.
Spécifications du projet
Fonctionnalités
1. CRUD complet (Create, Read, Update, Delete)
- Créer une nouvelle tâche
- Afficher toutes les tâches
- Modifier une tâche existante
- Supprimer une tâche
2. Persistance avec LocalStorage
- Sauvegarder les tâches dans le navigateur
- Charger les tâches au démarrage
- Synchronisation automatique
3. Interface utilisateur moderne
- Design responsive
- Animations fluides
- Feedback visuel
4. Fonctionnalités avancées
- Filtrer par statut (toutes, actives, terminées)
- Recherche de tâches
- Tri par date, priorité
- Statistiques (nombre total, terminées, actives)
Structure de données
{
id: 1,
titre: "Apprendre JavaScript",
description: "Maîtriser tous les concepts",
priorite: "haute",
date: "2026-01-26",
termine: false,
dateCreation: "2026-01-25T10:00:00Z"
}
Architecture recommandée
Structure de fichiers :
projet-todo/
├── index.html
├── css/
│ └── style.css
├── js/
│ ├── main.js # Point d'entrée
│ ├── models/
│ │ └── Task.js # Modèle de données
│ ├── services/
│ │ └── StorageService.js # Gestion LocalStorage
│ ├── controllers/
│ │ └── TaskController.js # Logique métier
│ └── views/
│ └── TaskView.js # Manipulation DOM
└── README.md
Guide de développement
Étape 1 : Modèle (Model)
// models/Task.js
class Task {
constructor(titre, description, priorite = "moyenne") {
this.id = Date.now();
this.titre = titre;
this.description = description;
this.priorite = priorite;
this.date = new Date().toISOString().split('T')[0];
this.termine = false;
this.dateCreation = new Date().toISOString();
}
toJSON() {
return {
id: this.id,
titre: this.titre,
description: this.description,
priorite: this.priorite,
date: this.date,
termine: this.termine,
dateCreation: this.dateCreation
};
}
static fromJSON(data) {
const task = new Task(data.titre, data.description, data.priorite);
task.id = data.id;
task.date = data.date;
task.termine = data.termine;
task.dateCreation = data.dateCreation;
return task;
}
}
Étape 2 : Service de stockage
// services/StorageService.js
class StorageService {
static STORAGE_KEY = 'todos';
static sauvegarder(tasks) {
const json = JSON.stringify(tasks.map(t => t.toJSON()));
localStorage.setItem(this.STORAGE_KEY, json);
}
static charger() {
const json = localStorage.getItem(this.STORAGE_KEY);
if (!json) return [];
const data = JSON.parse(json);
return data.map(d => Task.fromJSON(d));
}
}
Étape 3 : Controller
// controllers/TaskController.js
class TaskController {
constructor() {
this.tasks = StorageService.charger();
this.view = new TaskView(this);
}
ajouter(titre, description, priorite) {
const task = new Task(titre, description, priorite);
this.tasks.push(task);
this.sauvegarder();
this.view.afficher();
}
supprimer(id) {
this.tasks = this.tasks.filter(t => t.id !== id);
this.sauvegarder();
this.view.afficher();
}
modifier(id, donnees) {
const task = this.tasks.find(t => t.id === id);
if (task) {
Object.assign(task, donnees);
this.sauvegarder();
this.view.afficher();
}
}
marquerTermine(id) {
const task = this.tasks.find(t => t.id === id);
if (task) {
task.termine = !task.termine;
this.sauvegarder();
this.view.afficher();
}
}
sauvegarder() {
StorageService.sauvegarder(this.tasks);
}
filtrer(statut) {
switch(statut) {
case 'actives':
return this.tasks.filter(t => !t.termine);
case 'terminees':
return this.tasks.filter(t => t.termine);
default:
return this.tasks;
}
}
}
Étape 4 : View (Manipulation DOM)
// views/TaskView.js
class TaskView {
constructor(controller) {
this.controller = controller;
this.container = document.getElementById('tasks');
this.init();
}
init() {
// Écouteurs d'événements
document.getElementById('addTask').addEventListener('click', () => {
this.afficherFormulaire();
});
// Filtres
document.querySelectorAll('.filter').forEach(btn => {
btn.addEventListener('click', (e) => {
const statut = e.target.dataset.statut;
this.afficher(this.controller.filtrer(statut));
});
});
}
afficher(tasks = null) {
const tasksAAfficher = tasks || this.controller.tasks;
this.container.innerHTML = tasksAAfficher.map(task => this.renderTask(task)).join('');
this.attacherEventListeners();
}
renderTask(task) {
return `
<div class="task ${task.termine ? 'termine' : ''}" data-id="${task.id}">
<h3>${task.titre}</h3>
<p>${task.description}</p>
<span class="priorite ${task.priorite}">${task.priorite}</span>
<button class="toggle" data-id="${task.id}">
${task.termine ? 'Réactiver' : 'Terminer'}
</button>
<button class="delete" data-id="${task.id}">Supprimer</button>
</div>
`;
}
attacherEventListeners() {
document.querySelectorAll('.toggle').forEach(btn => {
btn.addEventListener('click', (e) => {
const id = parseInt(e.target.dataset.id);
this.controller.marquerTermine(id);
});
});
document.querySelectorAll('.delete').forEach(btn => {
btn.addEventListener('click', (e) => {
const id = parseInt(e.target.dataset.id);
if (confirm('Supprimer cette tâche ?')) {
this.controller.supprimer(id);
}
});
});
}
}
Étape 5 : Point d'entrée
// main.js
document.addEventListener('DOMContentLoaded', () => {
const controller = new TaskController();
controller.view.afficher();
});
Critères d'évaluation
Fonctionnalité (40%) :
- CRUD complet fonctionnel
- LocalStorage opérationnel
- Filtres et recherche
- Interface réactive
Code (30%) :
- Architecture modulaire (classes, modules)
- Code organisé et commenté
- Respect des bonnes pratiques
JavaScript (20%) :
- Utilisation appropriée des concepts
- POO avec classes
- Async/await si nécessaire
- Gestion d'erreurs
Design (10%) :
- Interface claire et moderne
- Responsive
- Animations fluides
Exercice - Développement
Suivez ces étapes :
-
Setup (30 min)
- Créez la structure de fichiers
- Configurez HTML de base
- Ajoutez le CSS minimal
-
Modèle (1h)
- Créez la classe Task
- Implémentez toJSON/fromJSON
- Testez avec console
-
Service (1h)
- Créez StorageService
- Testez sauvegarde/chargement
- Gèrez les erreurs
-
Controller (1h30)
- Créez TaskController
- Implémentez toutes les méthodes
- Testez la logique
-
View (2h)
- Créez TaskView
- Manipulez le DOM
- Attachez les événements
-
Intégration (1h)
- Connectez tout
- Testez toutes les fonctionnalités
- Corrigez les bugs
-
Améliorations (1h)
- Ajoutez les fonctionnalités bonus
- Améliorez l'UX
- Finalisez le design
Quiz de révision
Avant de commencer, vérifiez vos connaissances :
- Comment créer une classe en JavaScript ?
- Comment sauvegarder dans LocalStorage ?
- Comment manipuler le DOM ?
- Comment gérer les événements ?
- Comment organiser le code en modules ?
Ressources
Si vous êtes bloqué :
- Revisitez les modules précédents
- MDN Web Docs : developer.mozilla.org
- Stack Overflow pour problèmes spécifiques
Bonnes pratiques à respecter :
- Architecture modulaire
- Code propre et commenté
- Gestion d'erreurs appropriée
- Interface utilisateur claire
- Performance optimisée
Objectif final
Créer une application web interactive complète qui démontre :
- Maîtrise de la syntaxe JavaScript
- Compréhension de la POO
- Manipulation du DOM
- Gestion d'événements
- Persistance de données
- Architecture modulaire
- Bonnes pratiques
Validation : Vous avez terminé JavaScript quand votre application est fonctionnelle, bien structurée et utilise toutes les fonctionnalités apprises.
Félicitations ! Vous avez terminé l'apprentissage complet de JavaScript. Vous êtes maintenant capable de créer des applications web interactives professionnelles.