Tech2Elevate · Shopping Cart Project

How JavaScript
controls a webpage

A complete visual tour of every HTML tag, JavaScript function, array, and method used to build the shopping cart, with interactive labs you can click through.

<button>getElementById()addEventListener()cart.push().find().splice()innerHTMLdataset.id
Part 1 · HTML: tags, attributes, the DOM
Part 2 · Finding elements on the page
Part 3 · JS basics: variables, operators, objects
Part 4 · Arrays and array methods
Part 5 · Functions, building elements, events
Part 6 · Full cart walkthrough, bugs, recap

Use ← → arrow keys or the buttons below to navigate

The big idea

Every interaction follows the same four steps

HTML gives the page structure. JavaScript finds parts of it, waits for a person to act, then changes the data and the page.

1

HTML landmarks

Tags with id, class, and data-id labels.

Like street signs on a map

2

Find elements

getElementById, querySelector, querySelectorAll.

Like looking up an address

3

Listen for events

addEventListener("click", …) waits for the person to act.

Like a lookout on watch

4

Update data and page

Change the cart array, then redraw with updateCart().

Like updating a scoreboard

Where each idea shows up in the program

Week 2HTML product card: div, h2, p, img, button, class
Week 3CSS + cart section with ids: #cart-items, #cart-total
Week 4products array, getElementById, forEach, innerHTML
Week 5addEventListener, dataset.id, find, push
Week 6Quantity ++, totals, toFixed(2), updateCart()
Week 7findIndex, splice, listeners on new buttons
Part 1 · HTML

Three files, three jobs

The project folder holds three files. The HTML file connects the other two.

🦴

index.html

The structure: what is on the page.

🎨

styles.css

The style: colors, spacing, layout.

🧠

script.js

The behavior: what happens when you interact.

index.html: the browser reads top to bottom

<!DOCTYPE html>
<html>
  <head>
    <title>Tech Shop</title>
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <div id="product-list" class="product-grid"></div>

    <h2 class="section-title">Your Cart</h2>
    <p id="empty-cart-message">Your cart is empty.</p>
    <div id="cart-items" class="cart-items"></div>
    <div id="cart-total"></div>

    <script src="script.js"></script>
  </body>
</html>

Why it is ordered this way

<link>Goes in <head> so styles load before anything appears.
<script>Goes just before </body>. The browser reads top to bottom, so every element already exists when JavaScript looks for it.
empty ids#product-list and #cart-items start empty. They are placeholders JavaScript fills in later.
⚠ order bugIf <script> runs in <head>, getElementById("cart-items") returns null because the cart list has not been read yet.
Part 1 · HTML

Every HTML tag in the project

Click a tag to see what it does and where it appears on the page.

●●●Tech Shop
🛒 Tech Shop
🎮
Minecraft
$29.99
Add to Cart
🍬
Sour Patch Kids
$1.29
Add to Cart
Your Cart
Your cart is empty.
MinecraftQty: 1$29.99Remove
Total: $29.99
Invisible but important: <!DOCTYPE><head><title><link><script>
Part 1 · HTML

Attributes are labels JavaScript can read

Attributes go inside the opening tag as name="value". Hover a row to find it in the code.

One product card + the cart list

id
A unique name. Only one element per page should have it.getElementById("cart-items") · "#cart-items"
class
A shared label for groups, used by CSS and JS.".add-to-cart-button" · el.className · el.classList.add()
data-id
Your own custom data. Records which product a button belongs to.button.dataset.id → "game"
src
Where the image file lives.img.src
alt
Text read aloud by screen readers, and shown if the image fails to load.Accessibility!
href / rel
Used by <link> to connect styles.css.<link rel="stylesheet" href="styles.css">
Part 1 · The DOM

The DOM is the page as a family tree

The browser turns your HTML into a tree of objects called the Document Object Model. JavaScript starts at document and works its way down to find any element.

Every element object has properties you can read and change

.textContentThe plain text inside
.innerHTMLThe HTML inside, as a string
.classNameThe class attribute, as text
.classList.add()Add one class without removing others
.dataset.idReads the data-id attribute
.style.displayShow ("block") or hide ("none")
.appendChild()Add a child element inside this one
.addEventListener()React when something happens to it
Part 2 · Find

Three ways to find elements

Before JavaScript can change something, it has to find it. Each method asks the document a different kind of question.

ONE by id

getElementById

const cartItems =
  document.getElementById("cart-items");
✅ Returns one element. ❌ Returns null if no match.
⚠ No #, just the id name.
FIRST match

querySelector

document.querySelector("p");          // tag
document.querySelector(".my-div");    // class
document.querySelector("#myDiv");     // id
✅ Returns the first element that matches a CSS selector, or null.
ALL matches

querySelectorAll

const buttons = document
  .querySelectorAll(".add-to-cart-button");
buttons.forEach((button) => { ... });
✅ Returns a list of every match (can be empty). Loop through it with forEach.

Selector cheat sheet

WriteMeansMatches in our project
#nameelement with id="name"#cart-items → the cart <div>
.nameelements with class="name".product-card → every card
tagelements of that tagbutton → every button
a bb somewhere inside a#cart-items .cart-item → rows in the cart
[attr]by attribute value[data-id="candy"] → the candy button
Part 2 · Lab

🔬 Selector playground

Choose a method, then a selector, or type your own. Matching elements light up on the real page below, numbered in the order JavaScript finds them.

document.querySelectorAll("")

Your Cart

Your cart is empty.

MinecraftQty: 1
Total: $29.99
Press Run ▶

Part 3 · JavaScript basics

Variables, operators, and decisions

A variable is a labeled box for a value. const means the label always points to the same box; let means you can swap in a new value later.

StringText in quotes
"Minecraft"
NumberFor math
29.99
BooleanYes / no
true, false
Object / ArrayGroups of values
{ }, [ ]

Arithmetic

=assign: let total = 0
+ -add / subtract
* /multiply / divide: price * quantity
+=add to itself: total += itemTotal
++add 1: quantity++
--subtract 1: quantity--

Comparison (gives true / false)

===equal value and type ✅ use this
==equal value, loose (avoid)
!==not equal
> <greater / less than
>= <=or equal to

"1" === 1 is false: a string is not a number.

Try it: if / else in removeFromCart

cart[index].quantity =

if (cart[index].quantity > 1) {
  cart[index].quantity--; // take one away
} else {
  cart.splice(index, 1); // remove the row
}

Part 3 · Objects

Objects describe one thing

An object groups related values as key: value pairs. Each product is an object, and each cart item is a product object plus a quantity.

Lab: read, change, and add fields

// click a button

Why these matter in the cart

// One product object (Week 4)
const product = {
  id: "candy",
  name: "Sour Patch Kids",
  price: 1.29,
  image: "candy.jpg",
};

product.name;          // read  → "Sour Patch Kids"
product.price = 2.00;  // change a field
product.category = "Snack"; // add a new field

// Spread ... copies every field into a NEW object,
// then adds quantity (Week 5, addToCart)
cart.push({ ...product, quantity: 1 });

💡 The ... spread makes a copy, so changing the cart item's quantity doesn't change the original product.

Part 4 · Arrays

Arrays are ordered lists

The project uses two arrays: products (everything for sale) and cart (what the shopper picked). Positions are counted from 0.

products: the store shelf (never changes)

const products = [
  { id: "game",  name: "Minecraft",       price: 29.99 },
  { id: "candy", name: "Sour Patch Kids", price: 1.29  },
];
products[0].name;   // "Minecraft"
products.length;    // 2
🎮
[0]
🍬
[1]

cart: the shopping basket (changes on every click)

const cart = [];   // starts empty

// after clicking Minecraft twice and candy once:
[
  { id: "game",  name: "Minecraft", price: 29.99, quantity: 2 },
  { id: "candy", name: "Sour Patch Kids", price: 1.29, quantity: 1 },
]
🎮×2
[0]
🍬×1
[1]
ADD

push() adds to the end

REMOVE

pop() removes the last item · splice() removes from anywhere

SEARCH

find() returns the item · findIndex() returns its position

LOOP

forEach() runs code once for every item

Part 4 · Lab

🔬 Array method lab

Run each method and watch the array change. Output is shown in the console below, just like console.log.

let fruits = // length:
i=
remove last
i=
visit each
// console output
Part 5 · Functions

Functions are reusable recipes

A function is a named set of steps. You define it once, then call it whenever you need it. Hover each part:

function addToCart(productId) {
  const product = products.find(...);
  ...
}


addToCart("game"); // call it
Hover a colored part of the function ↑

Arrow functions: the short form

// These two do the same thing:
function (p) { return p.id === productId; }
(p) => p.id === productId

You see arrow functions inside forEach, find, and addEventListener. They're small functions handed to another function.

The 5 functions of the shopping cart

createProductHTML(product)
Takes one product object and returns its card HTML as a string. · Week 4
displayProducts()
Loops through products and puts a card on the page for each one. · Week 4
addToCart(productId)
Finds the product. If it's already in the cart, adds 1 to its quantity; if not, pushes a new item. · Weeks 5–6
updateCart()
Clears the cart list, then redraws every item, the Remove buttons, and the total. · Weeks 6–7
removeFromCart(productId)
Finds the item's index, then subtracts 1 from its quantity or splices it out. · Week 7
Part 5 · Functions

Who calls whom?

The functions call each other in a chain. Press a trigger to watch the chain run.

displayProducts()→products.forEach()→createElement("div")→createProductHTML(product)→appendChild(card)→addEventListener("click")
listener runs→button.dataset.id→addToCart(id)→products.find()→cart.find()→push() or quantity++→updateCart()
listener runs→removeFromCart(item.id)→cart.findIndex()→quantity-- or splice()→updateCart()
innerHTML = ""→let total = 0→cart.forEach()→price * quantity→createElement("div")→Remove button + listener→appendChild()→total.toFixed(2)

Key rule

Every time the cart array changes, call updateCart() so the page matches the data. The data is the source of truth; the page is a picture of it.

Part 5 · Change the page

🔬 Building new elements, step by step

createElement makes an element in memory. It is not on the page until appendChild places it there.

🧠 In memory (invisible)
🖥 On the page: <div class="cart-items">
Apple — $1.00
const row = document.createElement("div");
row.className = "cart-item"; // or row.classList.add("cart-item")
row.textContent = "Banana — $2.00";
row.setAttribute("data-id", "banana");
cartItems.appendChild(row); // now it's visible!
// the element's HTML will appear here

Template literals build HTML with values

const name = "Minecraft";
const price = 29.99;

// Backticks ` ` let you insert values with ${ }
card.innerHTML = `
  <h2>${name}</h2>
  <p>$${price.toFixed(2)}</p>
`;
// toFixed(2) → "29.99" (always 2 decimals)

Try it: innerHTML vs textContent

el.innerHTML = …
el.textContent = …

innerHTML reads tags as HTML. textContent shows them as plain text. Use textContent for plain words.

Part 5 · Listen

Event listeners make the page respond

An event is something that happens: a click, the mouse moving over an element, or a key press. A listener is the function that runs when its event happens.

button.addEventListener("click", () => {
  addToCart(button.dataset.id);
}
);
1. WHO
The element to watch, found with querySelectorAll
2. WHAT
The event name: "click", "mouseover", "keydown"
3. THEN
The function to run. It waits and does not run until the event happens.

Try three event types

"click"
0
"mouseover"
🙈Move your mouse over this box
"keydown"
⌨️

⚠ Elements created later need their listener when they're created

Remove buttons don't exist when the page loads, so querySelectorAll at the start can't find them. Attach the listener right after creating each one inside updateCart():

const removeButton = document.createElement("button");
removeButton.textContent = "Remove";
removeButton.addEventListener("click", () => removeFromCart(item.id));
Part 6 · Everything together

🔬 Watch the whole script.js run, line by line

#product-list

Your Cart

Your cart is empty.

Press "Load the page" to start.
Variables will appear here
Part 6 · Debugging

Common bugs and how to fix them

Open DevTools (right-click → Inspect → Console) and add console.log(something) to see what's really in a variable.

"Cannot read properties of null"
The id in getElementById doesn't match the HTML, or it includes a #.
✔ Copy the exact id from index.html
No products appear
displayProducts is defined but never called.
✔ Add displayProducts();
Cart data changes, page doesn't
The cart array was updated but the page was never redrawn.
✔ Call updateCart() after every change
Items appear twice
updateCart adds rows without clearing the old ones.
✔ Start with innerHTML = ""
Add button does nothing
Listeners were attached before the cards were created, or the class name has a typo.
✔ Attach after displayProducts()
find returns undefined
dataset.id is always a string. "1" === 1 is false.
✔ Use string ids, like id: "1"
Price shows 59.980000001
Computers can't store some decimals exactly.
✔ Display with .toFixed(2)
Remove button does nothing
No listener was attached when the button was created.
✔ Add addEventListener inside updateCart
Reference

Every tag, function, and method in one table

The pattern behind every interaction

Find the element→Listen for the event→Change the data→Redraw the page

Discussion: what does JavaScript need to know to update the correct part of the page?