handleEvent vs Traditional Event Handling
HTML
<div id="app">
<header>
<h1>Todo App - handleEvent Demo</h1>
<nav>
<button data-action="showActive">Active</button>
<button data-action="showCompleted">Completed</button>
<button data-action="showAll">All</button>
</nav>
</header>
<main>
<form id="todo-form">
<input
type="text"
id="todo-input"
placeholder="What needs to be done?"
required
/>
<button type="submit">Add Todo</button>
</form>
<div id="todo-stats">
<span id="total-count">0 total</span>
<span id="active-count">0 active</span>
<button id="clear-completed" data-action="clearCompleted">
Clear Completed
</button>
</div>
<ul id="todo-list">
<!-- Todos will be dynamically added here -->
</ul>
</main>
<footer>
<div id="memory-info">
<p>
<strong>Traditional Approach:</strong>
<span id="traditional-memory">~50KB</span> (bound functions)
</p>
<p>
<strong>handleEvent Approach:</strong>
<span id="handleevent-memory">~5KB</span> (1 handler)
</p>
</div>
</footer>
</div>
CSS
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
#app {
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
header {
text-align: center;
margin-bottom: 30px;
}
h1 {
color: #333;
margin: 0 0 20px;
}
nav button {
background: #007bff;
color: white;
border: none;
padding: 8px 16px;
margin: 0 5px;
border-radius: 4px;
cursor: pointer;
transition: background 0.2s;
}
nav button:hover {
background: #0056b3;
}
nav button.active {
background: #28a745;
}
#todo-form {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
#todo-input {
flex: 1;
padding: 10px;
border: 2px solid #ddd;
border-radius: 4px;
font-size: 16px;
}
#todo-form button {
background: #28a745;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
}
#todo-stats {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 10px;
background: #f8f9fa;
border-radius: 4px;
}
#clear-completed {
background: #dc3545;
color: white;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
}
#todo-list {
list-style: none;
padding: 0;
margin: 0;
}
.todo-item {
display: flex;
align-items: center;
padding: 12px;
border-bottom: 1px solid #eee;
transition: background 0.2s;
}
.todo-item:hover {
background: #f8f9fa;
}
.todo-item.completed {
opacity: 0.6;
text-decoration: line-through;
}
.todo-item.hidden {
display: none;
}
.todo-checkbox {
margin-right: 12px;
cursor: pointer;
}
.todo-text {
flex: 1;
cursor:...
JavaScript
// Single handleEvent-based Todo App
class TodoApp {
constructor() {
this.todos = [];
this.filter = 'all'; // 'all', 'active', 'completed'
this.nextId = 1;
// ONE event listener handles EVERYTHING
document.addEventListener('click', this);
document.addEventListener('submit', this);
document.addEventListener('input', this);
document.addEventListener('change', this);
this.updateStats();
this.updateMemoryInfo();
}
// The magic method - browser calls this automatically
handleEvent(event) {
switch(event.type) {
case 'click': this.handleClick(event); break;
case 'submit': this.handleSubmit(event); break;
case 'input': this.handleInput(event); break;
case 'change': this.handleChange(event); break;
}
}
handleClick(event) {
const action = event.target.dataset.action;
// Route to specific actions
if (action && this[action]) {
this[action](event);
return;
}
// Handle todo interactions
if (event.target.classList.contains('todo-delete')) {
this.deleteTodo(event);
} else if (event.target.classList.contains('todo-text')) {
this.toggleTodo(event);
}
}
handleSubmit(event) {
if (event.target.id === 'todo-form') {
event.preventDefault();
this.addTodo();
}
}
handleInput(event) {
// Real-time validation could go here
if (event.target.id === 'todo-input') {
// Example: auto-save draft, character count, etc.
}
}
handleChange(event) {
if (event.target.classList.contains('todo-checkbox')) {
this.toggleTodo(event);
}
}
// Action methods called via...