Web Development Foundation
Before you start
You need: stage 5, so there is an API to call.
Time: 36–44 classes.
Learning objective
Build the browser skills both frontend paths assume — semantic HTML, responsive CSS, JavaScript, the DOM, and calling the API from stage 5.
Topics
- Semantic HTML and forms
- CSS, the box model, Flexbox and Grid
- Responsive design
- JavaScript fundamentals, arrays and objects
- The DOM and events
- JSON,
fetch, promises andasync/await - Essential jQuery
- TypeScript basics
What this stage covers
Angular and React are both built on this. A component is HTML, CSS and TypeScript with a framework arranging them. Skipping to a framework without this stage means every layout problem and every undefined becomes framework magic rather than something you can reason about.
| Concept | Used later in |
|---|---|
| Semantic HTML | Component templates, stage 7 |
| CSS layout and responsiveness | Every screen |
| JavaScript arrays and objects | Rendering lists |
| The DOM and events | What frameworks do for you |
fetch and async/await | Calling the stage 5 API |
| JSON | The payload format throughout |
| TypeScript | Angular requires it; React benefits |
Three rules established here recur in every remaining stage:
- Client-side validation is a convenience, never a control. The API from stage 5 validates again, because Postman skips the browser entirely.
- CORS is fixed on the server. Nothing you write in JavaScript changes it, and a request that works in Postman and fails in the browser is the signature.
- The token lives in browser storage and is sent on every request. HTTP is stateless; the server remembers nothing.
Worked flow: the fee receipt
The receipt for Ravi Kumar (NCA-2024-0012) as a plain page calling the stage 5 API — before any framework.
<main class="receipt">
<h1>Fee Receipt</h1>
<dl class="receipt-details">
<dt>Receipt number</dt> <dd id="receiptNumber"></dd>
<dt>Student</dt> <dd id="studentName"></dd>
<dt>Roll number</dt> <dd id="rollNumber"></dd>
<dt>Class</dt> <dd id="className"></dd>
<dt>Amount paid</dt> <dd id="amountPaid"></dd>
<dt>Paid on</dt> <dd id="paidOn"></dd>
<dt>Balance</dt> <dd id="balance"></dd>
</dl>
<button id="printButton" type="button">Print</button>
</main>
<dl>, <dt> and <dd> are semantic — a description list is exactly what a receipt is. A screen reader announces the pairs correctly, and the print stylesheet can target them.
async function loadReceipt(paymentId) {
const token = localStorage.getItem("token");
const response = await fetch(`/api/fee-payments/${paymentId}/receipt`, {
headers: { "Authorization": `Bearer ${token}` }
});
if (response.status === 401) {
window.location.href = "/login";
return;
}
if (response.status === 404) {
document.getElementById("receiptNumber").textContent = "Receipt not found";
return;
}
if (!response.ok) {
document.getElementById("receiptNumber").textContent = "Could not load the receipt";
return;
}
const receipt = await response.json();
document.getElementById("receiptNumber").textContent = receipt.receiptNumber;
document.getElementById("studentName").textContent = receipt.studentName;
document.getElementById("rollNumber").textContent = receipt.rollNumber;
document.getElementById("className").textContent = receipt.className;
document.getElementById("amountPaid").textContent = formatCurrency(receipt.amountPaid);
document.getElementById("paidOn").textContent = formatDate(receipt.paidOn);
document.getElementById("balance").textContent = formatCurrency(receipt.balanceAfterPayment);
}
Every status code is handled separately, because each needs a different response — 401 redirects, 404 shows a message, 500 shows a different one. if (!response.ok) alone treats all three the same.
The token is read from storage and sent on every request. No cookie, no session on the server.
Note the camelCase field names. The API returns receiptNumber, not ReceiptNumber — the JSON convention differs from C#, and expecting the wrong casing produces undefined with no error.
@media print {
.no-print, #printButton, nav {
display: none;
}
.receipt {
max-width: 100%;
}
.receipt::after {
content: "nexcoding.in";
display: block;
margin-top: 2rem;
font-size: 0.75rem;
color: #666;
}
}
A print stylesheet is a real requirement here — the clerk prints this. Hide the navigation and the button; keep the content.
Where to learn it
| Topic | Read |
|---|---|
| HTML structure | Track 09 — HTML structure |
| Tables and forms | Track 09 — Tables and forms |
| Semantic layout | Track 09 — Semantic layout |
| CSS fundamentals | Track 09 — CSS fundamentals |
| Flexbox and Grid | Track 09 — CSS layout |
| Responsive design | Track 09 — Responsive design |
| JavaScript fundamentals | Track 09 — JavaScript fundamentals |
| Arrays and objects | Track 09 — Arrays and objects |
| The DOM and events | Track 09 — DOM and events |
| JSON, fetch, async | Track 09 — JSON, fetch, async |
| jQuery and TypeScript | Track 09 — jQuery and TypeScript |
| The frontend capstone | Track 09 — Frontend project |
Tools: Track 15 — Browser and frontend tooling.
Stage exercises
From the guided path syllabus:
Build a semantic form. A fee payment form with labels bound to inputs, correct input types, and validation attributes. Then submit it from Postman without any of them.
Recreate a responsive card layout. A student list that is a table on desktop and cards on mobile.
Render API data. Call the stage 5 receipt endpoint and render it, handling 200, 401, 404 and 500 differently.
Write a typed API client. In TypeScript, define a FeeReceipt interface matching the DTO and a getReceipt(paymentId: number): Promise<FeeReceipt> function.
Debugging drills
Fix layout overflow. Make a table overflow on mobile, find it in the Elements panel, and fix it with an overflow-x: auto container.
Investigate a console error. Render a receipt before the fetch resolves and read Cannot read properties of undefined.
Trace a failed network request. Call the API with an expired token, read the 401 in the Network tab, and decode the token to confirm exp is in the past.
Meet CORS. Serve the page from localhost:5173 against the API on localhost:7099 with no CORS policy. Read the error, confirm the same request works in Postman, then fix it on the server.
Practice
- Work through Track 09's twelve articles.
- Build the receipt page above and connect it to your stage 5 API.
- Handle 200, 401, 404 and 500 separately, and trigger each.
- Use
ReceiptNumberinstead ofreceiptNumberand watch the field render asundefined. - Write a print stylesheet that hides navigation and adds the
nexcoding.infooter. - Build a fee payment form with
requiredandmin, then submit an invalid payment from Postman. - Make the student list responsive — table on desktop, cards on mobile.
- Break CSS three ways — specificity, a wrong selector, a file that fails to load — and identify each in the Styles pane.
- Trigger a CORS error and fix it on the server, not the client.
- Store a token in
localStorage, decode it atjwt.io, and confirm theexpclaim. - Define TypeScript interfaces for
FeeReceiptandRecordPaymentRequest, and note the compile error when a field name is wrong.
Exercises 6 and 9 are the two that decide whether you understand where control actually lives.
You can now
- Build responsive, semantic pages
- Write JavaScript that manipulates the DOM and handles events
- Call your API with
fetchand handle each status code separately - Say why client-side validation is never the control
- Write foundational TypeScript
Review questions
- Why does client-side validation not remove the need for server-side validation?
- Why does a request that works in Postman fail in the browser with a CORS error?
- What happens when you read
ReceiptNumberfrom a JSON response that containsreceiptNumber? - Why must the token be sent on every request rather than once at sign-in?
Next: Choose Angular or React