JavaScript Third Lecture: Objects, DOM Manipulation, and Events
What We'll Learn Today
- Objects: Storing related data together
- DOM Manipulation: Making web pages interactive
- Event Handling: Responding to user actions
- Local Storage: Remembering user data
- Building a complete interactive web application
Objects: Organizing Related Data
Objects are collections of related properties and methods. They help us organize data that belongs together.
Creating Objects
// Object literal notation
let student = {
name: "Sarah",
age: 20,
major: "Computer Science",
gpa: 3.8,
isEnrolled: true
};
// Accessing object properties
console.log("Student name: " + student.name);
console.log("Student age: " + student.age);
console.log("GPA: " + student.gpa);
// Dot notation vs bracket notation
console.log(student.major); // Dot notation
console.log(student["major"]); // Bracket notation (useful for dynamic properties)
Adding and Modifying Properties
let car = {
brand: "Toyota",
model: "Camry",
year: 2022
};
// Adding new properties
car.color = "blue";
car.mileage = 15000;
// Modifying existing properties
car.year = 2023;
car.mileage += 5000;
console.log("=== Car Information ===");
console.log(`Brand: ${car.brand}`);
console.log(`Model: ${car.model}`);
console.log(`Year: ${car.year}`);
console.log(`Color: ${car.color}`);
console.log(`Mileage: ${car.mileage} miles`);
Objects with Methods
let calculator = {
// Properties
brand: "Scientific Calculator",
version: "1.0",
// Methods (functions inside objects)
add: function(a, b) {
return a + b;
},
subtract: function(a, b) {
return a - b;
},
multiply: function(a, b) {
return a * b;
},
divide: function(a, b) {
if (b === 0) {
return "Error: Cannot divide by zero!";
}
return a / b;
},
// Method using arrow function
power: (a, b) => {
return Math.pow(a, b);
}
};
// Using object methods
console.log("=== Calculator Tests ===");
console.log(`5 + 3 = ${calculator.add(5, 3)}`);
console.log(`10 - 4 = ${calculator.subtract(10, 4)}`);
console.log(`6 * 7 = ${calculator.multiply(6, 7)}`);
console.log(`15 / 3 = ${calculator.divide(15, 3)}`);
console.log(`2^8 = ${calculator.power(2, 8)}`);
Real-World Object Examples
// Game player object
let player = {
username: "GamerPro123",
level: 15,
health: 100,
score: 2500,
inventory: ["sword", "shield", "potion"],
// Method to take damage
takeDamage: function(damage) {
this.health -= damage;
if (this.health < 0) this.health = 0;
console.log(`${this.username} took ${damage} damage. Health: ${this.health}`);
},
// Method to gain experience
gainExp: function(exp) {
this.score += exp;
console.log(`${this.username} gained ${exp} experience. Total score: ${this.score}`);
},
// Method to add item to inventory
addItem: function(item) {
this.inventory.push(item);
console.log(`${this.username} found ${item}! Inventory: ${this.inventory.join(", ")}`);
}
};
// Using player methods
player.takeDamage(25);
player.gainExp(100);
player.addItem("magic ring");
// Bank account object
let bankAccount = {
accountNumber: "12345678",
ownerName: "John Smith",
balance: 1000.00,
accountType: "Checking",
deposit: function(amount) {
if (amount > 0) {
this.balance += amount;
console.log(`✅ Deposited $${amount}. New balance: $${this.balance.toFixed(2)}`);
} else {
console.log("❌ Invalid deposit amount");
}
},
withdraw: function(amount) {
if (amount > 0 && amount <= this.balance) {
this.balance -= amount;
console.log(`✅ Withdrew $${amount}. New balance: $${this.balance.toFixed(2)}`);
} else if (amount > this.balance) {
console.log("❌ Insufficient funds");
} else {
console.log("❌ Invalid withdrawal amount");
}
},
checkBalance: function() {
console.log(`💰 Account balance: $${this.balance.toFixed(2)}`);
return this.balance;
}
};
// Banking operations
console.log("\n=== Banking Operations ===");
bankAccount.checkBalance();
bankAccount.deposit(250);
bankAccount.withdraw(100);
bankAccount.withdraw(2000); // Should fail
DOM Manipulation: Making Web Pages Interactive
The Document Object Model (DOM) allows JavaScript to interact with HTML elements.
Selecting HTML Elements
// HTML structure we're working with:
/*
<div id="container">
<h1 id="title">Welcome to My Website</h1>
<p class="description">This is a paragraph</p>
<button id="changeButton">Click Me!</button>
<ul id="itemList">
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
*/
// Selecting elements by ID
let title = document.getElementById("title");
let button = document.getElementById("changeButton");
let container = document.getElementById("container");
// Selecting elements by class name
let description = document.getElementsByClassName("description")[0];
// Selecting elements by tag name
let paragraphs = document.getElementsByTagName("p");
// Modern selectors (recommended)
let titleModern = document.querySelector("#title"); // ID selector
let descModern = document.querySelector(".description"); // Class selector
let firstLi = document.querySelector("li"); // First li element
let allLis = document.querySelectorAll("li"); // All li elements
console.log("Title element:", title);
console.log("All list items:", allLis);
Changing Content and Styles
// Changing text content
title.textContent = "Welcome to JavaScript DOM!";
// Changing HTML content
description.innerHTML = "<strong>This text is now bold!</strong>";
// Changing styles
title.style.color = "blue";
title.style.fontSize = "36px";
title.style.textAlign = "center";
// Adding CSS classes
description.classList.add("highlight");
description.classList.add("important");
// Removing CSS classes
description.classList.remove("old-style");
// Toggling CSS classes
button.classList.toggle("active");
// Changing attributes
button.setAttribute("disabled", "true");
button.removeAttribute("disabled");
// Working with form inputs
/*
<input type="text" id="nameInput" placeholder="Enter your name">
<input type="number" id="ageInput" placeholder="Enter your age">
*/
let nameInput = document.querySelector("#nameInput");
let ageInput = document.querySelector("#ageInput");
// Getting input values
let userName = nameInput.value;
let userAge = parseInt(ageInput.value);
// Setting input values
nameInput.value = "John Doe";
ageInput.value = 25;
Creating and Adding Elements
// Creating new elements
let newParagraph = document.createElement("p");
newParagraph.textContent = "This paragraph was created with JavaScript!";
newParagraph.style.color = "green";
// Adding elements to the page
container.appendChild(newParagraph);
// Creating a list item and adding to existing list
let itemList = document.querySelector("#itemList");
let newItem = document.createElement("li");
newItem.textContent = "Item 3 (Added by JavaScript)";
itemList.appendChild(newItem);
// Creating a more complex element
let infoDiv = document.createElement("div");
infoDiv.innerHTML = `
<h3>Dynamic Content</h3>
<p>This entire section was created with JavaScript!</p>
<button onclick="alert('Hello from dynamic button!')">Dynamic Button</button>
`;
infoDiv.style.border = "2px solid #333";
infoDiv.style.padding = "10px";
infoDiv.style.margin = "10px 0";
container.appendChild(infoDiv);
Event Handling: Responding to User Actions
Events allow your JavaScript to respond to user interactions like clicks, key presses, and form submissions.
Basic Event Handling
// Method 1: Using onclick property
let clickButton = document.querySelector("#changeButton");
clickButton.onclick = function() {
alert("Button was clicked!");
};
// Method 2: Using addEventListener (recommended)
clickButton.addEventListener("click", function() {
console.log("Button clicked with addEventListener!");
});
// Method 3: Arrow function with addEventListener
clickButton.addEventListener("click", () => {
title.style.color = title.style.color === "red" ? "blue" : "red";
});
Different Types of Events
// Click events
button.addEventListener("click", function() {
console.log("Button clicked!");
});
// Mouse events
button.addEventListener("mouseenter", function() {
button.style.backgroundColor = "lightblue";
});
button.addEventListener("mouseleave", function() {
button.style.backgroundColor = "";
});
// Keyboard events
let textInput = document.querySelector("#nameInput");
textInput.addEventListener("keydown", function(event) {
console.log("Key pressed:", event.key);
});
textInput.addEventListener("keyup", function(event) {
let inputValue = event.target.value;
console.log("Current input:", inputValue);
});
// Form events
let form = document.querySelector("#userForm");
form.addEventListener("submit", function(event) {
event.preventDefault(); // Prevent page refresh
let name = nameInput.value;
let age = ageInput.value;
if (name === "" || age === "") {
alert("Please fill in all fields!");
return;
}
console.log(`Form submitted - Name: ${name}, Age: ${age}`);
});
// Window events
window.addEventListener("load", function() {
console.log("Page fully loaded!");
});
window.addEventListener("resize", function() {
console.log("Window resized to:", window.innerWidth, "x", window.innerHeight);
});
Interactive Examples
// Color changer
let colorButtons = document.querySelectorAll(".color-btn");
let colorBox = document.querySelector("#colorBox");
colorButtons.forEach(function(button) {
button.addEventListener("click", function() {
let color = button.dataset.color; // Get data-color attribute
colorBox.style.backgroundColor = color;
colorBox.textContent = `Color: ${color}`;
});
});
// Counter application
let counter = 0;
let counterDisplay = document.querySelector("#counterDisplay");
let incrementBtn = document.querySelector("#incrementBtn");
let decrementBtn = document.querySelector("#decrementBtn");
let resetBtn = document.querySelector("#resetBtn");
function updateDisplay() {
counterDisplay.textContent = counter;
counterDisplay.style.color = counter > 0 ? "green" : counter < 0 ? "red" : "black";
}
incrementBtn.addEventListener("click", function() {
counter++;
updateDisplay();
});
decrementBtn.addEventListener("click", function() {
counter--;
updateDisplay();
});
resetBtn.addEventListener("click", function() {
counter = 0;
updateDisplay();
});
// Initialize display
updateDisplay();
Local Storage: Remembering User Data
Local Storage allows you to save data in the user's browser that persists between sessions.
Basic Local Storage Operations
// Saving data to local storage
localStorage.setItem("userName", "John Doe");
localStorage.setItem("userAge", "25");
localStorage.setItem("userScore", "1500");
// Getting data from local storage
let savedName = localStorage.getItem("userName");
let savedAge = localStorage.getItem("userAge");
let savedScore = localStorage.getItem("userScore");
console.log("Saved name:", savedName);
console.log("Saved age:", savedAge);
console.log("Saved score:", savedScore);
// Removing specific item
localStorage.removeItem("userAge");
// Clearing all local storage
// localStorage.clear(); // Uncomment to clear all data
// Checking if item exists
if (localStorage.getItem("userName") !== null) {
console.log("User name is saved");
} else {
console.log("User name not found");
}
Saving Complex Data
// Saving objects and arrays (convert to JSON)
let userPreferences = {
theme: "dark",
language: "English",
notifications: true,
volume: 75
};
let favoriteColors = ["blue", "green", "purple"];
// Save object as JSON string
localStorage.setItem("userPreferences", JSON.stringify(userPreferences));
localStorage.setItem("favoriteColors", JSON.stringify(favoriteColors));
// Retrieve and parse JSON data
let savedPreferences = JSON.parse(localStorage.getItem("userPreferences"));
let savedColors = JSON.parse(localStorage.getItem("favoriteColors"));
console.log("Saved preferences:", savedPreferences);
console.log("Saved colors:", savedColors);
// Safe JSON parsing with error handling
function getStoredData(key) {
try {
let data = localStorage.getItem(key);
return data ? JSON.parse(data) : null;
} catch (error) {
console.error("Error parsing stored data:", error);
return null;
}
}
let preferences = getStoredData("userPreferences");
if (preferences) {
console.log("Theme:", preferences.theme);
console.log("Language:", preferences.language);
}
Mini Project: Interactive To-Do List
Let's combine everything we learned to create a complete to-do list application!
// To-Do List Application
let todoApp = {
tasks: [],
// Load tasks from local storage
loadTasks: function() {
let savedTasks = localStorage.getItem("todoTasks");
if (savedTasks) {
this.tasks = JSON.parse(savedTasks);
}
this.displayTasks();
},
// Save tasks to local storage
saveTasks: function() {
localStorage.setItem("todoTasks", JSON.stringify(this.tasks));
},
// Add new task
addTask: function(taskText) {
if (taskText.trim() === "") {
alert("Please enter a task!");
return;
}
let newTask = {
id: Date.now(), // Simple ID generation
text: taskText,
completed: false,
createdAt: new Date().toLocaleDateString()
};
this.tasks.push(newTask);
this.saveTasks();
this.displayTasks();
console.log("Task added:", newTask);
},
// Remove task
removeTask: function(taskId) {
this.tasks = this.tasks.filter(task => task.id !== taskId);
this.saveTasks();
this.displayTasks();
console.log("Task removed:", taskId);
},
// Toggle task completion
toggleTask: function(taskId) {
let task = this.tasks.find(task => task.id === taskId);
if (task) {
task.completed = !task.completed;
this.saveTasks();
this.displayTasks();
console.log("Task toggled:", task);
}
},
// Display all tasks
displayTasks: function() {
let taskList = document.querySelector("#taskList");
let taskCount = document.querySelector("#taskCount");
// Clear existing tasks
taskList.innerHTML = "";
// Display each task
this.tasks.forEach(task => {
let taskElement = document.createElement("div");
taskElement.className = "task-item";
taskElement.innerHTML = `
<div class="task-content ${task.completed ? 'completed' : ''}">
<input type="checkbox" ${task.completed ? 'checked' : ''}
onchange="todoApp.toggleTask(${task.id})">
<span class="task-text">${task.text}</span>
<span class="task-date">${task.createdAt}</span>
</div>
<button class="delete-btn" onclick="todoApp.removeTask(${task.id})">
🗑️ Delete
</button>
`;
taskList.appendChild(taskElement);
});
// Update task count
let completedCount = this.tasks.filter(task => task.completed).length;
taskCount.textContent = `Total: ${this.tasks.length} | Completed: ${completedCount}`;
},
// Clear all completed tasks
clearCompleted: function() {
this.tasks = this.tasks.filter(task => !task.completed);
this.saveTasks();
this.displayTasks();
console.log("Completed tasks cleared");
},
// Get app statistics
getStats: function() {
let total = this.tasks.length;
let completed = this.tasks.filter(task => task.completed).length;
let pending = total - completed;
return {
total: total,
completed: completed,
pending: pending,
completionRate: total > 0 ? Math.round((completed / total) * 100) : 0
};
}
};
// Initialize the app when page loads
document.addEventListener("DOMContentLoaded", function() {
todoApp.loadTasks();
// Add event listener for form submission
let addTaskForm = document.querySelector("#addTaskForm");
let taskInput = document.querySelector("#taskInput");
addTaskForm.addEventListener("submit", function(event) {
event.preventDefault();
todoApp.addTask(taskInput.value);
taskInput.value = ""; // Clear input
});
// Add event listener for clear completed button
let clearBtn = document.querySelector("#clearCompleted");
clearBtn.addEventListener("click", function() {
if (confirm("Are you sure you want to clear all completed tasks?")) {
todoApp.clearCompleted();
}
});
// Display stats button
let statsBtn = document.querySelector("#showStats");
statsBtn.addEventListener("click", function() {
let stats = todoApp.getStats();
alert(`📊 Todo List Stats:
Total Tasks: ${stats.total}
Completed: ${stats.completed}
Pending: ${stats.pending}
Completion Rate: ${stats.completionRate}%`);
});
});
// Keyboard shortcuts
document.addEventListener("keydown", function(event) {
// Press 'n' to focus on new task input
if (event.key === 'n' && !event.target.matches('input')) {
let taskInput = document.querySelector("#taskInput");
taskInput.focus();
event.preventDefault();
}
// Press 'c' to clear completed tasks
if (event.key === 'c' && !event.target.matches('input')) {
todoApp.clearCompleted();
event.preventDefault();
}
});
Practice Challenges
Challenge 1: Interactive Quiz App
let quizApp = {
questions: [
{
question: "What does JavaScript stand for?",
options: ["Java Script", "Just Script", "JavaScript", "None of the above"],
correct: 2
},
{
question: "Which symbol is used for comments in JavaScript?",
options: ["//", "/*", "#", "Both A and B"],
correct: 3
},
{
question: "What is the correct way to declare a variable?",
options: ["var x;", "let x;", "const x = 5;", "All of the above"],
correct: 3
}
],
currentQuestion: 0,
score: 0,
startQuiz: function() {
this.currentQuestion = 0;
this.score = 0;
this.displayQuestion();
},
displayQuestion: function() {
if (this.currentQuestion >= this.questions.length) {
this.showResults();
return;
}
let question = this.questions[this.currentQuestion];
let quizContainer = document.querySelector("#quizContainer");
quizContainer.innerHTML = `
<h3>Question ${this.currentQuestion + 1} of ${this.questions.length}</h3>
<p class="question-text">${question.question}</p>
<div class="options">
${question.options.map((option, index) => `
<button class="option-btn" onclick="quizApp.selectAnswer(${index})">
${option}
</button>
`).join('')}
</div>
<p class="score">Score: ${this.score}/${this.questions.length}</p>
`;
},
selectAnswer: function(selectedIndex) {
let question = this.questions[this.currentQuestion];
if (selectedIndex === question.correct) {
this.score++;
alert("Correct! 🎉");
} else {
alert(`Wrong! The correct answer was: ${question.options[question.correct]}`);
}
this.currentQuestion++;
this.displayQuestion();
},
showResults: function() {
let percentage = Math.round((this.score / this.questions.length) * 100);
let quizContainer = document.querySelector("#quizContainer");
let grade = percentage >= 80 ? "Excellent!" :
percentage >= 60 ? "Good!" :
percentage >= 40 ? "Fair" : "Need more practice";
quizContainer.innerHTML = `
<h2>Quiz Complete! 🏆</h2>
<p>Your Score: ${this.score}/${this.questions.length} (${percentage}%)</p>
<p>Grade: ${grade}</p>
<button onclick="quizApp.startQuiz()">Take Quiz Again</button>
`;
// Save high score
let highScore = localStorage.getItem("quizHighScore") || 0;
if (this.score > highScore) {
localStorage.setItem("quizHighScore", this.score);
alert("New high score! 🌟");
}
}
};
Remember This
"The DOM is your canvas, events are your brushes, and JavaScript is your paint. With these tools, you can create any interactive experience you can imagine!" 🎨
Task (Essential Practice)
Create a Personal Expense Tracker that includes:
- Objects to store expense data
- DOM manipulation to update the interface
- Event handling for user interactions
- Local storage to persist data
- Dynamic content creation
<!-- HTML structure (add this to your HTML file) -->
<div id="expenseTracker">
<h2>💰 Personal Expense Tracker</h2>
<form id="expenseForm">
<input type="text" id="expenseDescription" placeholder="Expense description" required>
<input type="number" id="expenseAmount" placeholder="Amount ($)" required step="0.01">
<select id="expenseCategory">
<option value="food">🍕 Food</option>
<option value="transport">🚗 Transportation</option>
<option value="entertainment">🎬 Entertainment</option>
<option value="utilities">⚡ Utilities</option>
<option value="other">📦 Other</option>
</select>
<button type="submit">Add Expense</button>
</form>
<div id="expenseSummary"></div>
<div id="expenseList"></div>
<button id="clearAll">Clear All Expenses</button>
</div>
// Starter code - complete this program
let expenseTracker = {
expenses: [],
// TODO: Complete these methods
addExpense: function(description, amount, category) {
// Create expense object with id, description, amount, category, date
// Add to expenses array
// Save to localStorage
// Update display
},
removeExpense: function(expenseId) {
// Remove expense from array by id
// Save to localStorage
// Update display
},
displayExpenses: function() {
// Show all expenses in the expenseList div
// Each expense should have description, amount, category, date, and delete button
},
calculateSummary: function() {
// Calculate total expenses
// Calculate expenses by category
// Display in expenseSummary div
},
loadExpenses: function() {
// Load expenses from localStorage
// Update display
},
saveExpenses: function() {
// Save expenses array to localStorage as JSON
}
};
// TODO: Add event listeners for:
// 1. Form submission to add new expense
// 2. Clear all button
// 3. Page load to initialize the app
Requirements:
- Use objects to structure expense data (id, description, amount, category, date)
- Use DOM manipulation to create and update expense list dynamically
- Use event handling for form submission and delete buttons
- Use local storage to persist expenses between browser sessions
- Display summary statistics (total spent, spending by category)
- Add proper form validation
Bonus Features:
- Add expense editing functionality
- Implement expense filtering by category
- Add date range filtering
- Create visual indicators for high spending categories!