On this page
Final project - Task manager
Project description
In this final project you will build a task manager that integrates all the concepts from the course. The goal is for you to see how all the pieces you learned fit together.
Concepts applied
| Lesson | Concept used in the project |
|---|---|
| Variables and types | Primitive types, const/let |
| Operators and control flow | Conditionals, switch |
| Modern functions | Arrow functions, closures, callbacks |
| Objects and arrays | Destructuring, spread |
| Array methods | filter, map, reduce, find |
| Strings | Template literals, includes, toLowerCase |
| DOM | createElement, classList, event listeners |
| Events | Event delegation, preventDefault |
| Promises | Handling asynchronous operations |
| Async/Await | HTTP requests |
| Fetch API | CRUD with a REST API |
| ES Modules | File organization |
| Modern patterns | Map, Set, private fields, Optional chaining |
Architecture
The project follows a layered architecture:
1. Model (Task)
The Task class encapsulates the data of a task with private fields (#id, #completed). It uses the constructor to validate and initialize, and exposes getters for read-only access.
2. Service (TaskStore)
The TaskStore manages the task collection using a Map for efficient access by ID. It implements a subscription system (Observer pattern) to notify changes.
3. View (DOM)
The view layer (not included in the example, but which you will build) uses DOM methods to render tasks and event delegation to handle interactions.
Proposed challenges
Extend the project with these progressive improvements:
Level 1 - Persistence
Save tasks to localStorage so they persist between reloads:
// Save
localStorage.setItem('tasks', JSON.stringify([...tasks]));
// Load
const saved = JSON.parse(localStorage.getItem('tasks') ?? '[]');Level 2 - DOM interface
Render tasks in the browser:
- Create a form to add tasks
- Display the list with filters (all, pending, completed)
- Use event delegation to handle clicks on delete and complete buttons
Level 3 - REST API
Connect the store to a REST API with fetch:
async function sync() {
const res = await fetch('/api/tasks');
const data = await res.json();
// update the local store
}Level 4 - Advanced search
Implement search with debounce to filter tasks as the user types:
function debounce(fn, ms) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), ms);
};
}Course recap
You have completed Essential JavaScript. You now master:
- Language fundamentals (variables, types, operators, control flow)
- Modern functions (arrow, closures, higher-order)
- Data structures (objects, arrays, Map, Set)
- DOM manipulation and event handling
- Asynchronous programming (promises, async/await, fetch)
- ES modules and modern patterns
The next step is to learn a framework like Angular to build complete and scalable web applications.
You have completed the Essential JavaScript course. The recommended next step is Angular for Developers.
// =============================================
// PROJECT: Task manager with JavaScript
// =============================================
// Applies everything learned in the course:
// - Modules and classes
// - Array methods
// - Async/await and Fetch
// - DOM and events
// - Modern patterns
// =============================================
// === MODEL: Task class ===
class Task {
#id;
#completed;
constructor({ title, description = '', priority = 'medium' }) {
this.#id = crypto.randomUUID();
this.title = title;
this.description = description;
this.priority = priority;
this.#completed = false;
this.createdAt = new Date();
}
get id() { return this.#id; }
get completed() { return this.#completed; }
toggleCompleted() {
this.#completed = !this.#completed;
}
toJSON() {
return {
id: this.#id,
title: this.title,
description: this.description,
priority: this.priority,
completed: this.#completed,
createdAt: this.createdAt.toISOString(),
};
}
}
// === SERVICE: TaskStore ===
class TaskStore {
#tasks = new Map();
#listeners = new Set();
add(data) {
const task = new Task(data);
this.#tasks.set(task.id, task);
this.#notify();
return task;
}
remove(id) {
const removed = this.#tasks.delete(id);
if (removed) this.#notify();
return removed;
}
toggleCompleted(id) {
const task = this.#tasks.get(id);
task?.toggleCompleted();
this.#notify();
}
getAll(filter = 'all') {
const list = [...this.#tasks.values()];
switch (filter) {
case 'pending':
return list.filter(t => !t.completed);
case 'completed':
return list.filter(t => t.completed);
default:
return list;
}
}
search(term) {
const lower = term.toLowerCase();
return this.getAll().filter(t =>
t.title.toLowerCase().includes(lower) ||
t.description.toLowerCase().includes(lower)
);
}
get stats() {
const all = this.getAll();
return {
total: all.length,
completed: all.filter(t => t.completed).length,
pending: all.filter(t => !t.completed).length,
byPriority: Object.groupBy(all, t => t.priority),
};
}
subscribe(callback) {
this.#listeners.add(callback);
return () => this.#listeners.delete(callback);
}
#notify() {
this.#listeners.forEach(fn => fn(this.getAll()));
}
}
// === USAGE ===
const store = new TaskStore();
// Subscribe to changes
store.subscribe((tasks) => {
console.log(`Tasks updated: ${tasks.length}`);
});
// Add tasks
const t1 = store.add({
title: 'Learn JavaScript',
description: 'Complete the Essential JS course',
priority: 'high',
});
store.add({
title: 'Practice array methods',
priority: 'medium',
});
store.add({
title: 'Read MDN documentation',
priority: 'low',
});
// Complete a task
store.toggleCompleted(t1.id);
// View stats
console.log(store.stats);
// Filter
console.log('Pending:', store.getAll('pending'));
// Search
console.log('Search:', store.search('array'));
Sign in to track your progress