JavaScript To-Do List Project: State-Driven UI ఆర్కిటెక్చర్ (Mini Project)

🟨 JavaScript (ES2026+) 🟢 Lesson 21 of 25 📂 Part 04: DOM & Events (Page 4 of 4) ⏱️ 16 min read
📌 Covered in this project: State-Driven UI · Railway Timetable Analogy · CRUD Operations in JS · Pure Array Methods (push, filter, map) · Event Delegation · Task Counter & Filters

సాధారణంగా చాలామంది To-Do List ను ఒక సాధారణ బిగినర్ ప్రాజెక్ట్ అనుకుంటారు. కానీ పెద్ద పెద్ద టెక్ కంపెనీలలో ఒక సాఫ్ట్‌వేర్ ఇంజనీర్ ఆలోచనా విధానాన్ని పరీక్షించడానికి ఇది అత్యుత్తమ గీటురాయి! ఒక యూజర్ ఇంటర్‌ఫేస్ వెనుక డేటాను ఎలా నిర్వహించాలో (Architecture) అర్థం చేసుకోవడానికి ఇది పునాది.

రైల్వే స్టేషన్ టైమ్ టేబుల్ బోర్డ్ అనాలజీ (Railway Display Board Analogy):
రైల్వే స్టేషన్‌లో ఏ ప్లాట్‌ఫారమ్‌పై ఏ రైలు వస్తుందో చూపించే పెద్ద డిజిటల్ బోర్డ్ ఉంటుంది. ఆ బోర్డుపై వివరాలు మార్చడానికి ఎవరూ నిచ్చెన వేసుకుని వచ్చి నేరుగా బోర్డుపై చాక్‌పీస్‌తో రాయరు!
స్టేషన్ మాస్టర్ రూమ్‌లో ఒక మెయిన్ కంప్యూటర్ (Central Database) ఉంటుంది. దానిలో సమయం లేదా ప్లాట్‌ఫారమ్ నంబర్ మారగానే, బయట ఉన్న డిజిటల్ బోర్డ్ ఆటోమేటిక్‌గా రీ-రెండర్ అవుతుంది!
వెబ్ డెవలప్‌మెంట్‌లో కూడా ఇదే నియమం: UI ని నేరుగా మార్చకూడదు; ముందుగా మన 'State' (డేటా) ని మార్చాలి, స్క్రీన్ దానంతట అదే అప్‌డేట్ అవ్వాలి!

ఈ ప్రాజెక్ట్‌తో మనం Part 04 (DOM & Events) ని విజయవంతంగా పూర్తి చేసుకుంటున్నాం. భవిష్యత్తులో మీరు React, Vue లేదా Angular నేర్చుకునేటప్పుడు వాడే State-Driven Architecture ని కేవలం కొన్ని స్వచ్ఛమైన జావాస్క్రిప్ట్ లైన్లలో ఎలా నిర్మించాలో ఇక్కడ నేర్చుకుందాం.

1చెత్త పద్ధతి (DOM Mess) vs State-Driven UI

చాలా వెబ్‌సైట్లు మరియు ట్యుటోరియల్స్ నేర్పించే అతిపెద్ద తప్పు: బటన్ నొక్కగానే నేరుగా document.createElement("li") చేసి స్క్రీన్ పై అతికించేయడం.

అంశం పాత చెత్త పద్ధతి (Direct DOM Manipulation) ప్రొఫెషనల్ పద్ధతి (State-Driven UI)
డేటా ఎక్కడుంది? స్క్రీన్ పై ఉన్న HTML ట్యాగ్స్ లోపలే చిక్కుకుపోతుంది. ✅ Single Source of Truth: జావాస్క్రిప్ట్ అరే (tasks = []) లో స్పష్టంగా ఉంటుంది.
టాస్క్ కౌంటర్ లెక్క document.querySelectorAll("li").length అని ప్రతిసారీ స్క్రీన్‌ని వెతకాలి. ✅ అత్యంత వేగవంతం: tasks.length తో కంప్యూటర్ మెమరీ నుండే క్షణంలో తెలుస్తుంది.
సర్వర్‌కు పంపడం స్క్రీన్ పై ఉన్న టెక్స్ట్‌ని మళ్లీ కష్టపడి జేసన్ గా మార్చాలి. ✅ సిద్ధంగా ఉంటుంది: JSON.stringify(tasks) అని నేరుగా పంపవచ్చు.
2Data Model: ప్రొఫెషనల్ Task Object నిర్మాణం

ఒక టాస్క్‌ని కేవలం సాదా స్ట్రింగ్ ("బ్రెడ్ కొనాలి") గా నిల్వ చేయకూడదు. ఎందుకంటే యూజర్ ఒకే పేరుతో రెండు వేర్వేరు పనులు రాయవచ్చు. కాబట్టి ప్రతి టాస్క్‌కి ఒక ప్రత్యేక గుర్తింపు (Unique Identity) ఉండాలి:

📦 ది గోల్డెన్ టాస్క్ మోడల్ (Task Object Structure):

{
  id: Date.now(), // మిల్లీసెకన్ల ఆధారిత ప్రత్యేక ID
  text: "JavaScript ప్రాజెక్ట్ పూర్తి చేయాలి", // టాస్క్ వివరణ
  completed: false // పని పూర్తయిందా లేదా (Boolean)
}

Date.now() ఎల్లప్పుడూ నిరంతరం పెరిగే సంఖ్యను ఇస్తుంది కాబట్టి, వేల టాస్క్‌లు ఉన్నా ఏ రెండు టాస్క్‌ల ID లు ఎప్పటికీ కలవవు!

3Array CRUD ఆపరేషన్స్ (push, filter, map)

మన To-Do లిస్ట్ అంతా జావాస్క్రిప్ట్ లోని 3 శక్తివంతమైన అరే మెథడ్స్ చుట్టూనే తిరుగుతుంది:

  • Create (చేర్చడం): tasks.push(newTask) ➔ అరే చివరిలో కొత్త పనిని చేరుస్తుంది.
  • Update (పూర్తయినట్లు మార్చడం): tasks.map(t => t.id === targetId ? {...t, completed: !t.completed} : t) ➔ సంబంధిత పని యొక్క స్థితిని తిప్పివేస్తుంది (Toggle).
  • Delete (తొలగించడం): tasks.filter(t => t.id !== targetId) ➔ ఆ ఐడీ లేని మిగిలిన పనులను మాత్రమే ఉంచి, ఆ ఒక్కదాన్ని తుడిచివేస్తుంది!
4Master Code Demo: కాంపాక్ట్ To-Do State ఇంజిన్

ఎటువంటి అనవసరమైన పొడవాటి కోడ్ లేకుండా, కేవలం 16 లైన్లలో Add, Toggle, మరియు Delete ఆపరేషన్లను నిర్వహించే స్వచ్ఛమైన కాంపాక్ట్ ఇంజిన్ ఇది:

JavaScript — Compact To-Do State Engine ▶ Run Code
// 1. సెంట్రల్ స్టేట్ (Single Source of Truth)
let tasks = [];

// 2. టాస్క్ జోడించడం (Create)
function addTask(text) {
  if (!text || !text.trim()) return false;
  tasks.push({ id: Date.now(), text: text.trim(), completed: false });
  return true;
}

// 3. పూర్తి అయినట్లు/కాకపోయినట్లు మార్చడం (Toggle Update)
function toggleTask(id) {
  tasks = tasks.map(t => t.id === id ? { ...t, completed: !t.completed } : t);
}

// 4. టాస్క్ తొలగించడం (Delete via Filter)
function deleteTask(id) {
  tasks = tasks.filter(t => t.id !== id);
}

// డెమో రన్ & టెస్టింగ్
addTask("JavaScript DOM ప్రాక్టీస్ చేయాలి");
console.log("టాస్క్ చేరింది:", tasks[0].text, "| పూర్తయిందా?:", tasks[0].completed);

toggleTask(tasks[0].id);
console.log("టిక్ కొట్టిన తర్వాత:", tasks[0].completed);

deleteTask(tasks[0].id);
console.log("డిలీట్ తర్వాత మొత్తం టాస్క్‌లు:", tasks.length);
Output:
టాస్క్ చేరింది: JavaScript DOM ప్రాక్టీస్ చేయాలి | పూర్తయిందా?: false
టిక్ కొట్టిన తర్వాత: true
డిలీట్ తర్వాత మొత్తం టాస్క్‌లు: 0
  • కేవలం 3 స్వచ్ఛమైన ఫంక్షన్లతో యాప్ యొక్క మొత్తం కోర్ లాజిక్ సిద్ధమైంది.
  • deleteTask లో filter() వాడటం వల్ల ఒరిజినల్ అరే సురక్షితంగా మార్పు చెందుతుంది.
5ప్రొడక్షన్‌లో ప్రాజెక్ట్‌ను విరిచేసే 5 తప్పులు

బిగినర్స్ ప్రాజెక్టులు ఇంటర్వ్యూలలో తిరస్కరణకు గురికావడానికి గల ప్రధాన కారణాలు:

1. Unique ID బదులు Array Index వాడటం:

ఇండెక్స్ 0, 1, 2 లపై ఆధారపడితే, మీరు మొదటి ఐటమ్‌ను డిలీట్ చేసినప్పుడు మిగిలిన అన్ని ఐటమ్స్ ఇండెక్స్‌లు మారిపోయి తప్పుడు టాస్క్ డిలీట్ అవుతుంది! ఎల్లప్పుడూ స్థిరమైన id వాడాలి.

2. State మార్చకుండా నేరుగా DOM ని మాత్రమే తొలగించడం:

li.remove() అని స్క్రీన్ పై తీసేసినా, మెమరీలోని tasks అరేలో ఆ డేటా అలాగే ఉండిపోతుంది (Ghost Data Bug).

3. ఖాళీ స్పేస్‌లను అనుమతించడం:

యూజర్ స్పేస్ బార్ నొక్కి యాడ్ చేస్తే ఖాళీ బుల్లెట్ పాయింట్ రాకుండా text.trim() తప్పనిసరిగా తనిఖీ చేయాలి.

4. ప్రతి లిస్ట్ ఐటమ్‌కి విడివిడిగా Event Listener పెట్టడం:

100 టాస్క్‌లు చేరితే 100 లిజనర్లు మెమరీని నింపేస్తాయి. పేరెంట్ <ul> పై ఒకే ఒక్క Event Delegation వాడాలి.

5. XSS రక్షణ లేకపోవడం:

టాస్క్ టెక్స్ట్‌ను innerHTML లో పెట్టకూడదు; హ్యాకర్లు స్క్రిప్ట్ పంపే ప్రమాదం ఉంది. ఎల్లప్పుడూ textContent మాత్రమే వాడాలి.

6Real-World Try-It: Live Task Analytics & Filter Engine

యూజర్లు తమ పనులలో ఎన్ని మిగిలి ఉన్నాయి, ఎన్ని పూర్తయ్యాయి అని చూసే లైవ్ కౌంటర్ మరియు ఫిల్టర్ ఇంజిన్ (All / Active / Completed):

🚀 మీరే స్వయంగా Try చేయండి! (Task Analytics Calculator)

ఈ కోడ్‌ను కంపైలర్ లో రన్ చేసి ఫిల్టర్ మార్చి ఫలితాలను గమనించండి:

JavaScript — Task Analytics & Filter Engine ▶ Run in Compiler
// ఫిల్టరింగ్ మరియు లైవ్ కౌంటర్ అనలిటిక్స్ ఫంక్షన్
function getTaskAnalytics(taskList, filterType = "all") {
  const total = taskList.length;
  const completedCount = taskList.filter(t => t.completed).length;
  const activeCount = total - completedCount;

  // ఫిల్టర్ ప్రకారం అవసరమైన పనులను మాత్రమే చూపించడం
  let filtered = taskList;
  if (filterType === "active") filtered = taskList.filter(t => !t.completed);
  if (filterType === "completed") filtered = taskList.filter(t => t.completed);

  return {
    total,
    completed: completedCount,
    active: activeCount,
    visibleTasks: filtered.map(t => t.text)
  };
}

// శాంపిల్ డేటా
const myTasks = [
  { id: 1, text: "HTML/CSS పూర్తి చేయడం", completed: true },
  { id: 2, text: "JavaScript ప్రాజెక్ట్ రాయడం", completed: false },
  { id: 3, text: "AdSense అప్రూవల్ చెక్ చేయడం", completed: false }
];

console.log("యాక్టివ్ (చేయాల్సినవి):", getTaskAnalytics(myTasks, "active"));
console.log("పూర్తయినవి:", getTaskAnalytics(myTasks, "completed"));
Output:
యాక్టివ్ (చేయాల్సినవి): { total: 3, completed: 1, active: 2, visibleTasks: [ 'JavaScript ప్రాజెక్ట్ రాయడం', 'AdSense అప్రూవల్ చెక్ చేయడం' ] }
పూర్తయినవి: { total: 3, completed: 1, active: 2, visibleTasks: [ 'HTML/CSS పూర్తి చేయడం' ] }
👉 Our Compiler లో JavaScript రన్ చేయండి
7ఆలోచింపజేసే ఇంటర్వ్యూ ప్రశ్నలు & సమాధానాలు

ఈ ప్రాజెక్ట్ ఆధారంగా టెక్ ఇంటర్వ్యూలలో అడిగే కీలక ప్రశ్నలు:

  1. DOM లో నేరుగా మార్పులు చేయకుండా State-Driven ఆర్కిటెక్చర్ ఎందుకు వాడాలి?
  2. టాస్క్‌లను డిలీట్ చేయడానికి splice() కంటే filter() ఎందుకు మెరుగైనది?
  3. కొత్తగా చేర్చిన టాస్క్‌ల డిలీట్ బటన్‌లకు కూడా ఈవెంట్ లిజనర్లు స్వయంచాలకంగా ఎలా పనిచేస్తాయి?
  4. టాస్క్ ఐడీ కోసం Date.now() ఎందుకు వాడతాం?
  5. యూజర్ బ్రౌజర్ రీఫ్రెష్ చేసినా ఈ టాస్క్‌లు పోకుండా ఉండాలంటే ఏ బ్రౌజర్ ఫీచర్ వాడాలి?
  6. యూజర్ ఎంట్రీ చేసిన టెక్స్ట్‌ని డిస్‌ప్లే చేసేటప్పుడు XSS దాడి జరగకుండా ఎలాంటి జాగ్రత్త తీసుకోవాలి?
👉 సమాధానాలు మరియు వివరణలు చూడండి (Click to Expand)

1. సమాధానం: స్టేట్ అనేది సింగిల్ సోర్స్ ఆఫ్ ట్రూత్ (Single Source of Truth). డేటా ఒకే చోట ఉండటం వల్ల కౌంటర్లు, ఫిల్టర్లు, మరియు సర్వర్‌కు పంపడం చాలా సులభం అవుతుంది.

2. సమాధానం: filter() అసలు అరేని పాడుచేయకుండా కొత్త అరేని రిటర్న్ చేస్తుంది (Immutability). దీనివల్ల ఊహించని బగ్స్ రావు.

3. సమాధానం: Event Delegation ద్వారా. పేరెంట్ <ul> పై ఒకే లిజనర్ ఉండటం వల్ల భవిష్యత్తులో ఎన్ని కొత్త బటన్లు వచ్చినా బుబ్లింగ్ ద్వారా క్లిక్ ఈవెంట్ పేరెంట్‌కు చేరుతుంది.

4. సమాధానం: ఇది ప్రస్తుత మిల్లీసెకన్లను ఇస్తుంది, కాబట్టి ప్రతి టాస్క్‌కి ఒక ప్రత్యేకమైన (Unique) ఐడీ లభిస్తుంది.

5. సమాధానం: localStorage (ఇది మనం తదుపరి Part 05 లో నేర్చుకుంటాం).

6. సమాధానం: ఎప్పుడూ textContent మాత్రమే వాడాలి, innerHTML లో యూజర్ టెక్స్ట్‌ని కలపకూడదు.

📌 సారాంశం (Quick Summary):

  • State-First: ముందు డేటాను మార్చండి, ఆపై UI ని రెండర్ చేయండి.
  • Unique IDs: టాస్క్‌లను ట్రాక్ చేయడానికి ఎల్లప్పుడూ Date.now() వాడండి.
  • Array Methods: చేర్చడానికి push(), మార్చడానికి map(), తీసివేయడానికి filter().
  • Event Delegation: ప్రతి బటన్‌కు కాకుండా పేరెంట్‌కు ఒకే లిజనర్ పెట్టండి.
  • భద్రత: ఎల్లప్పుడూ trim() మరియు textContent వాడండి.

🎉 అభినందనలు! Part 04 పూర్తయింది →

ఇంతటితో మీరు DOM మరియు Events ని పూర్తి స్థాయి ప్రాక్టికల్ ప్రాజెక్ట్‌తో మాస్టర్ చేశారు!
ఇప్పుడు మనం కోర్సులోని చివరి మరియు అత్యంత ప్రతిష్టాత్మకమైన విభాగానికి చేరుకున్నాం: Part 05: Modern & Advanced JavaScript.
తర్వాతి పాఠంలో ఇంటర్వ్యూలలో అత్యధికంగా అడిగే Scope, Hoisting & Closures లోని రహస్యాలను తేటతెల్లం చేసుకుందాం!

22. Scope, Hoisting & Closures →