⚡ धडा 04 — JavaScript आणि events: फलक जिवंत होतो
📍 तुम्ही इथे आहात: 12 पैकी धडा 04 · मागे: lesson-03-css-layout · पुढे: lesson-05-state-components
📦 या ब्रँचमध्ये काय आहे
धडे 01–03, आणि वागणे: elements शोधणे, events ऐकणे, DOM बदलणे, आणि fetch ने काउंटरला बोलावणे — प्रत्येक request च्या तीन चेहऱ्यांसह.
🧒 5 वर्षांच्या मुलाला समजावल्यासारखे
लावलेला फलक म्हणजे फक्त एक poster. त्याला लोक वापरतात असा फलक बनवायला तीन गोष्टी घडाव्या लागतात:
- ऐका 👂 — "जेव्हा वर्ग filter बदलतो…", "जेव्हा form
पाठवला जातो…". ते म्हणजे
addEventListener. Form वाला handlere.preventDefault()ने सुरू होतो, कारण form चे मूळ वागणे म्हणजे संपूर्ण पान reload करणे. - ठरवा 🧠 — काय बदलले ते वाचा, form valid आहे ते तपासा, काउंटरकडे data मागा.
- पुन्हा रंगवा 🖼️ — फलकावर नवीन cards लावा. आपण
<template>मधून elements बनवतो आणिtextContentset करतो (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"
❓ काय
- शोधणे:
document.querySelector('#id'),querySelectorAll. जे पुन्हा पुन्हा वापरता ते cache करून ठेवा. - Events:
el.addEventListener('click' | 'change' | 'submit' | 'input', fn). Handler ला एकeventमिळतो:e.target,e.preventDefault(),e.stopPropagation(). Events झाडात वर bubble होतात — list वरचा एकच listener प्रत्येक card ची सेवा करू शकतो (delegation). - DOM बदलणे:
textContent(सुरक्षित),replaceChildren(...nodes)(संपूर्ण list एका झटक्यात बदला),classList.toggle,el.hidden,template.content.cloneNode(true). - fetch + async/await:
const r = await fetch(url);r.okतपासा (404 मुळे throw होत नाही!);await r.json(). नेहमी timeout (AbortSignal.timeout), नेहमीtry/catch/finally. - Forms:
new FormData(form)→Object.fromEntries(…);input.checkValidity()तुम्हाला browser चे स्वतःचे validation देते. - Modules आणि scope: आपली file
"use strict"सह IIFE मध्ये गुंडाळलेली आहे, म्हणजे काहीही global पानावर गळत नाही; खरे apps<script type="module">वापरतात.
🤔 का
कारण प्रत्येक 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 आणि वापरण्याजोगा फलक यांच्यातला हाच फरक.
⚠️ नेहमीच्या चुका
- form submit वर
e.preventDefault()विसरणे - 404/500 वर
fetchthrow करेल असे गृहीत धरणे — ते फक्त network errors वरच reject होते;r.okतपासा innerHTML = userText(XSS — lesson 11)- timeout नाही, म्हणून अडकलेला काउंटर फलकाला कायमचा अडकवतो
render()च्या आत listeners जोडणे — प्रत्येक वेळी पुन्हा रंगवताना ते साचत जातात
🏭 प्रत्यक्ष वापरात हे का महत्त्वाचे: front-end चा सर्वात सामान्य bug report म्हणजे "ते फक्त फिरत राहते". जवळजवळ नेहमी कारण: timeout नाही,
r.okतपासणी नाही, किंवा error चा चेहराच नाही. या धड्यातलेtry/catch/finallyहे तिन्ही टाळते.
⏭️ पुढे
फलक चालतो — पण सत्य DOM भर विखुरलेले आहे. State आणि components: सत्याचा एकच स्रोत, आणि UI = render(state).
git checkout lesson-05-state-components