🏫 The School›📌 UI›⚡ धडा 04 — JavaScript आणि events: फलक जिवंत होतो
🖼️ See the drawing + lab 🏠 Course home 🌿 Branch on GitHub ✏️ View source
🖼️ आकृती आणि labThe drawing + lab पूर्ण पानावर उघडा ↗Open full page ↗

⚡ धडा 04 — JavaScript आणि events: फलक जिवंत होतो

📍 तुम्ही इथे आहात: 12 पैकी धडा 04 · मागे: lesson-03-css-layout · पुढे: lesson-05-state-components


📦 या ब्रँचमध्ये काय आहे

धडे 01–03, आणि वागणे: elements शोधणे, events ऐकणे, DOM बदलणे, आणि fetch ने काउंटरला बोलावणे — प्रत्येक request च्या तीन चेहऱ्यांसह.

🧒 5 वर्षांच्या मुलाला समजावल्यासारखे

लावलेला फलक म्हणजे फक्त एक poster. त्याला लोक वापरतात असा फलक बनवायला तीन गोष्टी घडाव्या लागतात:

  1. ऐका 👂 — "जेव्हा वर्ग filter बदलतो…", "जेव्हा form पाठवला जातो…". ते म्हणजे addEventListener. Form वाला handler e.preventDefault() ने सुरू होतो, कारण form चे मूळ वागणे म्हणजे संपूर्ण पान reload करणे.
  2. ठरवा 🧠 — काय बदलले ते वाचा, form valid आहे ते तपासा, काउंटरकडे data मागा.
  3. पुन्हा रंगवा 🖼️ — फलकावर नवीन cards लावा. आपण <template> मधून elements बनवतो आणि textContent set करतो (data सोबत innerHTML कधीच नाही — तसे केल्यास <img onerror=…> नावाचा विद्यार्थी तुमच्या फलकावर code चालवतो; lesson 11).

काउंटरशी बोलणे म्हणजे fetch, आणि त्याचे नेहमी तीन चेहरे असतात: loading (तसे सांगा, आणि list busy म्हणून चिन्हांकित करा), success (cards काढा), error (काय चुकले ते सौम्यपणे सांगा). जो फलक फक्त success चा चेहरा काढतो, तो काउंटरला शिंक आली की रिकामे पान दाखवतो.

🗺️ आकृती

sequenceDiagram
    participant U as 👆 user
    participant B as 📌 board (app.js)
    participant C as 🏢 counter (/api/students)
    U->>B: 1 change #class-filter / submit #enrol-form
    B->>B: 2 e.preventDefault() · validate · update state
    B->>C: 3 fetch(…, {signal: AbortSignal.timeout(5000)})
    C-->>B: 4 200 {items:[…]} — or 400/503
    B->>U: 5 render(): cards, or "Could not load: 503"

❓ काय

🤔 का

कारण प्रत्येक interactive पान हेच चक्र कायम चालवते: event → काहीतरी बदला → पुन्हा रंगवा. Frameworks पुन्हा रंगवणे आपोआप करतात (lesson 07), पण ते चक्र बदलत नाहीत — आणि काही चुकीचे वागले, की तुम्ही याच पातळीवर debug करता.

🔧 कसे (या repo मध्ये)

ui/app.js चे भाग 3 आणि 4: load() आणि enrol() fetching करतात (timeout, r.ok तपासणी आणि loading नेहमी साफ करणाऱ्या finally सह); भाग 4 च्या तळाशी असलेले दोन addEventListener calls हीच फलक माणसाला प्रतिसाद देतो अशी एकमेव ठिकाणे आहेत.

🧪 करून पाहा

python3 ui/mock_api.py
# 1) see all three faces — in ui/app.js change API to '/api/students?slow=1', reload: "Loading…" for 2.5 s
#    then '?fail=1': "Could not load: 503 Service Unavailable". Put it back.
# 2) delete e.preventDefault() in the submit handler, enrol someone, and watch the page reload (and lose the message)
# 3) add a listener of your own: a "Clear" button that resets state.filter and calls render()
# 4) in DevTools → Console:  document.querySelectorAll('.card').length

✅ तपासा — तुम्हाला काय दिसायला हवे

?slow=1 सह list फिकी होते (aria-busy) आणि status "Loading…" म्हणते; ?fail=1 सह तुम्हाला लाल "Could not load: 503" मिळते आणि रिकामे पान दिसत नाही. preventDefault शिवाय URL मध्ये ?name=… जोडले जाते आणि सगळे reset होते — तुम्ही दाबून ठेवत होता ते मूळ वागणे.

🏁 तुम्ही आत्ताच काय सिद्ध केले

तुम्ही माणसाची कृती state बदलाशी आणि state बदल पुन्हा रंगवण्याशी जोडला, आणि एक request सुरक्षितपणे fail होताना पाहिली — demo आणि वापरण्याजोगा फलक यांच्यातला हाच फरक.

⚠️ नेहमीच्या चुका

🏭 प्रत्यक्ष वापरात हे का महत्त्वाचे: front-end चा सर्वात सामान्य bug report म्हणजे "ते फक्त फिरत राहते". जवळजवळ नेहमी कारण: timeout नाही, r.ok तपासणी नाही, किंवा error चा चेहराच नाही. या धड्यातले try/catch/finally हे तिन्ही टाळते.

⏭️ पुढे

फलक चालतो — पण सत्य DOM भर विखुरलेले आहे. State आणि components: सत्याचा एकच स्रोत, आणि UI = render(state).

git checkout lesson-05-state-components

⚡ Lesson 04 — JavaScript & events: the board comes alive

📍 You are here: Lesson 04 of 12 · Previous: lesson-03-css-layout · Next: lesson-05-state-components


📦 What's in this branch

Lessons 01–03, plus behaviour: finding elements, listening for events, changing the DOM, and calling the counter with fetch — including the three faces of every request.

🧒 Explain like I'm 5

A pinned-up board is a poster. To make it a board people use, three things have to happen:

  1. Listen 👂 — "when the class filter changes…", "when the form is submitted…". That is addEventListener. The form one starts with e.preventDefault(), because a form's default is to reload the whole page.
  2. Decide 🧠 — read what changed, check the form is valid, ask the counter for data.
  3. Repaint 🖼️ — put new cards on the board. We build elements from a <template> and set textContent (never innerHTML with data — that is how a student called <img onerror=…> runs code on your board; lesson 11).

Talking to the counter is fetch, and it always has three faces: loading (say so, and mark the list busy), success (draw the cards), error (say what went wrong, kindly). A board that only draws the success face is a board that shows an empty page whenever the counter sneezes.

🗺️ Diagram

sequenceDiagram
    participant U as 👆 user
    participant B as 📌 board (app.js)
    participant C as 🏢 counter (/api/students)
    U->>B: 1 change #class-filter / submit #enrol-form
    B->>B: 2 e.preventDefault() · validate · update state
    B->>C: 3 fetch(…, {signal: AbortSignal.timeout(5000)})
    C-->>B: 4 200 {items:[…]} — or 400/503
    B->>U: 5 render(): cards, or "Could not load: 503"

❓ What

🤔 Why

Because this is the loop every interactive page runs, forever: event → change something → repaint. Frameworks make the repaint automatic (lesson 07), but they do not change the loop — and when something misbehaves, you debug it at this level.

🔧 How (in this repo)

ui/app.js sections 3 and 4: load() and enrol() do the fetching (with timeout, r.ok check and a finally that always clears loading); the two addEventListener calls at the bottom of section 4 are the only places the board reacts to a human.

🧪 Try it

python3 ui/mock_api.py
# 1) see all three faces — in ui/app.js change API to '/api/students?slow=1', reload: "Loading…" for 2.5 s
#    then '?fail=1': "Could not load: 503 Service Unavailable". Put it back.
# 2) delete e.preventDefault() in the submit handler, enrol someone, and watch the page reload (and lose the message)
# 3) add a listener of your own: a "Clear" button that resets state.filter and calls render()
# 4) in DevTools → Console:  document.querySelectorAll('.card').length

✅ Verify — what you should see

With ?slow=1 the list dims (aria-busy) and the status says "Loading…"; with ?fail=1 you get a red "Could not load: 503" and no blank page. Without preventDefault the URL gains ?name=… and everything resets — the default you were suppressing.

🏁 What you just proved

You wired a human action to a state change to a repaint, and you saw a request fail safely — the difference between a demo and a usable board.

⚠️ Common mistakes

🏭 Why this matters in production: the most common front-end bug report is "it just spins". Almost always: no timeout, no r.ok check, or no error face. The try/catch/finally in this lesson prevents all three.

⏭️ Next

The board works — but the truth is scattered across the DOM. State and components: one source of truth, and UI = render(state).

git checkout lesson-05-state-components
← Previouscss layoutNext →state components

This page is the lesson's README from the lesson-04-javascript-events branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.