Module 6 · Web Development with JavaScript
The DOM and events
Find elements with querySelector, react to typing and clicks with event listeners, and update the page live (the balance after a payment) while keeping the calculation in a plain, testable function.
About 15 minutes
The problem
On the old page, customers typed an amount, pressed Pay, waited for a whole new page, and only then saw what they'd still owe. Many typed the full invoice total instead of the balance, and the payment was refused. The page should tell them, as they type, what their balance will be.
The concept
Finding elements
JavaScript
const amount = document.querySelector("#amount"); // CSS selectors
const output = document.querySelector("#after-payment");Reading and changing them
input.value is what's typed (always text). element.textContent = "..." changes visible text safely. Avoid innerHTML with anything a user typed: it can run as HTML.
Events
JavaScript
amount.addEventListener("input", () => { /* runs on every keystroke */ });
form.addEventListener("submit", (event) => { event.preventDefault(); /* ... */ });Keep logic out of event handlers
Put the calculation in a plain function that takes values and returns a result. The event handler only reads the page, calls the function, and writes the result. The function can then be tested without a page (lesson 9).
Announce changes
aria-live="polite" on an element makes screen readers read out its new text when it changes.
Example
First the plain function: given what's due and what was typed, describe the balance after paying.
JavaScript
function balanceAfter(dueKobo, typed) {
const cleaned = typed.replace(/[₦,\s]/g, "");
if (cleaned === "") return { ok: false, message: "" };
if (!/^\d+(\.\d{1,2})?$/.test(cleaned)) return { ok: false, message: "Enter an amount like 5000 or 5000.50" };
const [naira, kobo = ""] = cleaned.split(".");
const amountKobo = Number(naira) * 100 + Number(kobo.padEnd(2, "0"));
if (amountKobo === 0) return { ok: false, message: "Enter an amount above zero" };
if (amountKobo > dueKobo) return { ok: false, message: "That's more than you owe" };
return { ok: true, amountKobo, remainingKobo: dueKobo - amountKobo };
}
for (const typed of ["5000", "₦17,830.50", "17830.51", "50.5", "abc", "0"]) {
console.log(JSON.stringify(typed), "->", JSON.stringify(balanceAfter(1783050, typed)));
}"5000" -> {"ok":true,"amountKobo":500000,"remainingKobo":1283050}
"₦17,830.50" -> {"ok":true,"amountKobo":1783050,"remainingKobo":0}
"17830.51" -> {"ok":false,"message":"That's more than you owe"}
"50.5" -> {"ok":true,"amountKobo":5050,"remainingKobo":1778000}
"abc" -> {"ok":false,"message":"Enter an amount like 5000 or 5000.50"}
"0" -> {"ok":false,"message":"Enter an amount above zero"}The amount is turned into kobo by splitting at the decimal point, never through a float. Now wire it to the page from lesson 4. Add this inside <main>, after the form, then the script before </body>:
HTML
<p id="after-payment" aria-live="polite"></p>
<script>
const DUE_KOBO = 1783050;
const naira = new Intl.NumberFormat("en-NG", { style: "currency", currency: "NGN" });
const amountInput = document.querySelector("#amount");
const afterPayment = document.querySelector("#after-payment");
// balanceAfter() from the example goes here, unchanged.
amountInput.addEventListener("input", () => {
const result = balanceAfter(DUE_KOBO, amountInput.value);
afterPayment.textContent = result.ok
? `After this payment you'll owe ${naira.format(result.remainingKobo / 100)}`
: result.message;
});
</script>Type 5000 and the line under the form reads "After this payment you'll owe ₦12,830.50"; type the full balance and it reads "After this payment you'll owe ₦0.00"; type one kobo too much and it says "That's more than you owe", before anything is sent.
Walkthrough
- Add the code to
pay.htmland try the amounts from the example. - Disable the Pay button while the amount isn't valid (
button.disabled = !result.ok). - Why does the handler use
textContentrather thaninnerHTML? - Write a handler for a "Pay full balance" button (the task below).
Practice
Practice
What is remainingKobo after typing "5000" against a balance of 1,783,050 kobo?
Task
6 minWrite JavaScript for a "Pay full balance" button (id pay-all): when clicked, it fills the amount input with the full balance in naira (like "17830.50") and updates the message the same way typing does.
Your work is checked for
- Selects the pay-all button
- Listens for click
- Sets the input's value
- Formats kobo as naira with two decimals
- Updates the message (dispatches input or calls the same code)
Check your understanding
Answer every question to check.