🎯 Learning Objectives
By the end of this lesson, you will be able to:
- Build a complete interactive web application
- Combine all concepts from Module 2
- Use DOM manipulation, events, and localStorage
- Create a functional to-do list with add/remove/complete features
- Apply modern JavaScript practices
📚 Project Overview
We'll build a complete to-do list application that allows users to: - Add new tasks - Mark tasks as complete - Remove tasks - Persist data in localStorage - Have a clean, interactive interface
🏗️ Project Structure
todo-app/
├── index.html
├── style.css
└── script.js
📝 HTML Structure
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>To-Do List App</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>My To-Do List</h1>
<form id="todoForm">
<input type="text" id="todoInput" placeholder="Add a new task..." required>
<button type="submit">Add Task</button>
</form>
<ul id="todoList"></ul>
<div class="stats">
<p>Total: <span id="totalCount">0</span></p>
<p>Completed: <span id="completedCount">0</span></p>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
🎨 CSS Styling
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
background-color: #f5f5f5;
padding: 20px;
}
.container {
max-width: 600px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
text-align: center;
color: #333;
margin-bottom: 30px;
}
#todoForm {
display: flex;
gap: 10px;
margin-bottom: 30px;
}
#todoInput {
flex: 1;
padding: 12px;
border: 2px solid #ddd;
border-radius: 5px;
font-size: 16px;
}
#todoInput:focus {
outline: none;
border-color: #007bff;
}
button {
padding: 12px 20px;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background-color: #0056b3;
}
#todoList {
list-style: none;
}
.todo-item {
display: flex;
align-items: center;
padding: 15px;
margin-bottom: 10px;
background-color: #f8f9fa;
border-radius: 5px;
border-left: 4px solid #007bff;
}
.todo-item.completed {
opacity: 0.6;
border-left-color: #28a745;
}
.todo-item.completed .todo-text {
text-decoration: line-through;
}
.todo-text {
flex: 1;
margin-left: 10px;
}
.todo-actions {
display: flex;
gap: 10px;
}
.toggle-btn, .delete-btn {
padding: 8px 12px;
border: none;
border-radius: 3px;
cursor: pointer;
font-size: 14px;
}
.toggle-btn {
background-color: #28a745;
color: white;
}
.toggle-btn:hover {
background-color: #218838;
}
.delete-btn {
background-color: #dc3545;
color: white;
}
.delete-btn:hover {
background-color: #c82333;
}
.stats {
display: flex;
justify-content: space-between;
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid #ddd;
}
.stats p {
font-weight: bold;
color: #666;
}
💻 JavaScript Functionality
class TodoApp {
constructor() {
this.todos = this.loadTodos();
this.todoForm = document.getElementById('todoForm');
this.todoInput = document.getElementById('todoInput');
this.todoList = document.getElementById('todoList');
this.totalCount = document.getElementById('totalCount');
this.completedCount = document.getElementById('completedCount');
this.init();
}
init() {
this.todoForm.addEventListener('submit', (e) => this.addTodo(e));
this.renderTodos();
this.updateStats();
}
addTodo(e) {
e.preventDefault();
const text = this.todoInput.value.trim();
if (!text) return;
const todo = {
id: Date.now(),
text: text,
completed: false,
createdAt: new Date().toISOString()
};
this.todos.push(todo);
this.todoInput.value = '';
this.saveTodos();
this.renderTodos();
this.updateStats();
}
toggleTodo(id) {
const todo = this.todos.find(t => t.id === id);
if (todo) {
todo.completed = !todo.completed;
this.saveTodos();
this.renderTodos();
this.updateStats();
}
}
deleteTodo(id) {
this.todos = this.todos.filter(t => t.id !== id);
this.saveTodos();
this.renderTodos();
this.updateStats();
}
renderTodos() {
this.todoList.innerHTML = '';
this.todos.forEach(todo => {
const li = document.createElement('li');
li.className = `todo-item ${todo.completed ? 'completed' : ''}`;
li.innerHTML = `
<input type="checkbox" ${todo.completed ? 'checked' : ''}
onchange="app.toggleTodo(${todo.id})">
<span class="todo-text">${todo.text}</span>
<div class="todo-actions">
<button class="toggle-btn" onclick="app.toggleTodo(${todo.id})">
${todo.completed ? 'Undo' : 'Complete'}
</button>
<button class="delete-btn" onclick="app.deleteTodo(${todo.id})">
Delete
</button>
</div>
`;
this.todoList.appendChild(li);
});
}
updateStats() {
this.totalCount.textContent = this.todos.length;
this.completedCount.textContent = this.todos.filter(t => t.completed).length;
}
saveTodos() {
localStorage.setItem('todos', JSON.stringify(this.todos));
}
loadTodos() {
const todosJson = localStorage.getItem('todos');
return todosJson ? JSON.parse(todosJson) : [];
}
}
// Initialize the app
const app = new TodoApp();
🎯 Key Features Implemented
- Add Tasks - Form submission with validation
- Toggle Completion - Checkbox and button functionality
- Delete Tasks - Remove tasks from the list
- Persistent Storage - Data saved in localStorage
- Statistics - Total and completed task counts
- Responsive Design - Clean, modern interface
🎯 Key Takeaways
- Classes organize complex application logic
- Event listeners handle user interactions
- DOM manipulation updates the interface
- localStorage persists data between sessions
- Modern JavaScript features make code cleaner
🚀 Next Steps
Congratulations! You've completed Module 2. You now understand:
- Scope and hoisting
- Destructuring and spread/rest operators
- Template literals
- Modules and imports/exports
- Classes and object-oriented programming
- Error handling
- DOM manipulation
- Event handling
- JSON and localStorage
- Building complete applications
Ready for Module 3: Advanced JavaScript! 🎉
Next Module: Module 3: Advanced JavaScript