ব্রাউজার DOM: ওয়েব পেজের প্রাণকেন্দ্র এবং জাভাস্ক্রিপ্টের জাদুকরী স্পর্শ (পর্ব ১)
ওয়েব ডেভেলপমেন্টের জগতে যারা নতুন পা রেখেছেন, তাদের জন্য DOM (Document Object Model) এবং জাভাস্ক্রিপ্ট কীভাবে এটি ব্যবহার করে ওয়েব পেজকে জীবন্ত করে তোলে, তা বোঝা অত্যন্ত জরুরি। এই সিরিজটি তাদের জন্যই, যারা জাভাস্ক্রিপ্টের হাতেখড়ি থেকে শুরু করে DOM ম্যানুপুলেশনের গভীরতম বিষয়গুলো সহজ ভাষায় শিখতে চান। আজকের প্রথম পর্বে আমরা DOM-এর মৌলিক ধারণা এবং এর গঠন নিয়ে আলোচনা করব।
DOM আসলে কী? 🧐
সহজ কথায়, DOM হলো একটি ওয়েব পেজের গঠন যা একটি অবজেক্ট মডেলে রূপান্তরিত হয়। যখন কোনো ওয়েব পেজ ব্রাউজারে লোড হয়, ব্রাউজার সেই HTML ডকুমেন্টটিকে একটি অবজেক্ট-ভিত্তিক কাঠামোতে পরিবর্তন করে। এই কাঠামোকেই আমরা DOM বলি। জাভাস্ক্রিপ্ট এই DOM-কেই ব্যবহার করে ওয়েব পেজের কন্টেন্ট, গঠন এবং স্টাইল পরিবর্তন করতে পারে, যার ফলে ওয়েব পেজটি ইন্টারেক্টিভ হয়ে ওঠে। [cite: 1]
ধরুন, আপনার একটি HTML ফাইল আছে। সেই ফাইলের প্রতিটি ট্যাগ (যেমন <html>
, <head>
, <body>
, <div>
, <h1>
ইত্যাদি) DOM-এ এক একটি অবজেক্ট হিসেবে পরিচিত হয়। [cite: 1] আর এই পুরো ব্যাপারটাই ঘটে window
অবজেক্টের অধীনে, যা ব্রাউজারের প্রধান বা গ্লোবাল অবজেক্ট। [cite: 2, 3]
DOM-এর গঠন: একটি গাছের মতো 🌳
DOM-এর গঠনকে একটি গাছের শাখার মতো কল্পনা করা যেতে পারে, যেখানে প্রতিটি শাখা-প্রশাখা হলো এক একটি HTML এলিমেন্ট বা নোড। [cite: 3] এই কাঠামোকে নোড ট্রি (Node Tree) বলা হয়।
- সবচেয়ে উপরে থাকে
document
অবজেক্ট। [cite: 2] - তার নিচে থাকে
<html>
এলিমেন্ট। <html>
এর দুটি প্রধান শাখা হলো<head>
এবং<body>
। [cite: 2]- এরপর
<head>
এর ভেতরে<title>
,<meta>
ইত্যাদি এবং<body>
এর ভেতরে<div>
,<h1>
,<p>
,<script>
ইত্যাদি এলিমেন্টগুলো ক্রমান্বয়ে সাজানো থাকে। [cite: 2]
এই যে প্রতিটি এলিমেন্ট, এরা প্রত্যেকেই DOM-এর এক একটি অবজেক্ট। [cite: 8]
DOM-কে চিনে নেওয়া: ব্রাউজার কনসোলের মাধ্যমে 🕵️♀️
আমরা ব্রাউজারের ডেভেলপার কনসোল ব্যবহার করে এই DOM অবজেক্টকে দেখতে পারি।
console.dir(document)
: এই কমান্ডটি কনসোলে পুরোdocument
অবজেক্ট এবং এর সকল প্রোপার্টি ও মেথড দেখায়। [cite: 7]typeof(document)
: এটি"object"
রিটার্ন করবে, কারণdocument
একটি অবজেক্ট। [cite: 7]
document
অবজেক্টের মধ্যে অসংখ্য প্রোপার্টি ও মেথড রয়েছে। [cite: 7] যেমন:
document.title
: এটি ওয়েব পেজের টাইটেল দেখায় এবং আমরা চাইলে এটি পরিবর্তনও করতে পারি। [cite: 7] যেমন,document.title = "নতুন টাইটেল";
লিখলে পেজের টাইটেল বদলে যাবে।document.URL
: পেজের বর্তমান URL দেখায়। [cite: 8]document.head
: HTML ডকুমেন্টের<head>
সেকশনটিকে অবজেক্ট হিসেবে দেখায়। [cite: 8]document.domain
: পেজের ডোমেইন নেম দেখায়। [cite: 8]
document.all
: সব HTML এলিমেন্টের সংগ্রহশালা (তবে ব্যবহারে সাবধান!) ⚠️
document.all
একটি বিশেষ অবজেক্ট, যা HTML ডকুমেন্টের সব এলিমেন্টকে একটি কালেকশনে (HTMLCollection) ধারণ করে। [cite: 10] এটি দেখতে অনেকটা অ্যারের মতো হলেও, এটি সত্যিকারের অ্যারে নয়। [cite: 10] তাই, অ্যারের সব অপারেশন এর উপর সরাসরি চালানো যায় না। [cite: 10]
আমরা for...of
লুপ ব্যবহার করে document.all
-এর প্রতিটি এলিমেন্ট দেখতে পারি: [cite: 11]
for (let element of document.all) {
console.log(element);
}
তবে, document.all[5] = "নতুন কিছু";
এভাবে সরাসরি কোনো এলিমেন্টের মান পরিবর্তন করা উচিত নয়। [cite: 11] এতে অনাকাঙ্ক্ষিত সমস্যা বা বাগ দেখা দিতে পারে। [cite: 11]
জাভাস্ক্রিপ্ট ও DOM ম্যানুপুলেশন: কী কী করা যায়? ✨
জাভাস্ক্রিপ্টের মাধ্যমে আমরা DOM-এর উপর পূর্ণ নিয়ন্ত্রণ পাই। [cite: 9] এর মানে হলো:
- Read (পড়া): DOM থেকে যেকোনো এলিমেন্টকে খুঁজে বের করে তার তথ্য পড়তে পারি। [cite: 6]
- Create (তৈরি করা): DOM-এর মধ্যে নতুন HTML এলিমেন্ট যোগ করতে পারি। [cite: 5]
- Update (আপডেট করা): বিদ্যমান কোনো এলিমেন্টের কন্টেন্ট, অ্যাট্রিবিউট বা স্টাইল পরিবর্তন করতে পারি। [cite: 6]
- Delete (মুছে ফেলা): DOM থেকে কোনো এলিমেন্টকে সরিয়ে ফেলতে পারি। [cite: 5]
এই চারটি মূল অপারেশনকে সংক্ষেপে CRUD (Create, Read, Update, Delete) বলা হয়। [cite: 3]
আজকের মতো এটুকুই! আমরা জানলাম DOM কী, এর গঠন কেমন এবং জাভাস্ক্রিপ্ট কীভাবে এর সাথে প্রাথমিক মিথস্ক্রিয়া করে। পরবর্তী পর্বে আমরা DOM থেকে এলিমেন্ট সিলেক্ট করার বিভিন্ন পদ্ধতি এবং সেগুলো নিয়ে আরও বিস্তারিত কাজ করা শিখব। সাথেই থাকুন!
ব্রাউজার DOM: ওয়েব পেজের প্রাণকেন্দ্র এবং জাভাস্ক্রিপ্টের জাদুকরী স্পর্শ (পর্ব ২)
আগের পর্বে আমরা DOM কী, এর গঠন এবং জাভাস্ক্রিপ্টের সাথে এর প্রাথমিক সম্পর্ক নিয়ে আলোচনা করেছি। আমরা জেনেছি কীভাবে document
অবজেক্ট ব্যবহার করে DOM-এর বিভিন্ন অংশে ঢুঁ মারা যায়। আজকের দ্বিতীয় পর্বে, আমরা শিখব কীভাবে DOM থেকে নির্দিষ্ট HTML এলিমেন্টগুলোকে আরও ভালোভাবে খুঁজে বের করতে হয় বা " ধরতে" হয়। কারণ, কোনো এলিমেন্টকে পরিবর্তন করার আগে তাকে সঠিকভাবে সিলেক্ট করাটা জরুরি।
document
অবজেক্ট: আরও কিছু খুঁটিনাটি 🧐
আমরা console.dir(document)
ব্যবহার করে document
অবজেক্টের বিস্তারিত রূপ দেখেছি। [cite: 1] এই অবজেক্টের মধ্যে শুধু যে HTML এলিমেন্টগুলোই থাকে তা নয়, আরও কিছু বিল্ট-ইন প্রোপার্টি ও মেথড থাকে। যেমন:
document.images
: ডকুমেন্টের সব<img>
ট্যাগকে একটি কালেকশনে দেখায়। [cite: 1]document.forms
: সব<form>
এলিমেন্টকে সংগ্রহ করে। [cite: 1]document.links
: সব<a>
(অ্যাঙ্কর) ট্যাগ, যাদেরhref
অ্যাট্রিবিউট আছে, তাদের একটি কালেকশন দেখায়। [cite: 1]
এই কালেকশনগুলো ব্যবহার করে আমরা নির্দিষ্ট ধরনের এলিমেন্টগুলোর সাথে কাজ করতে পারি। document
অবজেক্টের মধ্যে থাকা বিভিন্ন মেথড ব্যবহার করেই আমরা DOM-এ নতুন এলিমেন্ট তৈরি (Create), বিদ্যমান এলিমেন্ট পড়া (Read), আপডেট (Update) এবং মুছে ফেলা (Delete) অর্থাৎ CRUD অপারেশনগুলো করতে পারি। [cite: 1]
১. নির্দিষ্ট এলিমেন্টকে ID দিয়ে ধরা: getElementById()
🎯
যদি কোনো HTML এলিমেন্টের একটি ইউনিক id
অ্যাট্রিবিউট থাকে, তাহলে document.getElementById("আপনার-আইডি")
মেথড ব্যবহার করে খুব সহজেই সেই এলিমেন্টটিকে জাভাস্ক্রিপ্টে নিয়ে আসা যায়। [cite: 1]
ধরুন, আপনার HTML-এ একটি হেডার আছে:
<h1 id="main-header">পুরোনো টাইটেল</h1>
জাভাস্ক্রিপ্টে এটিকে ধরতে হলে:
const headerElement = document.getElementById("main-header");
এখন headerElement
ভ্যারিয়েবলটি ঐ <h1>
এলিমেন্টের অবজেক্টকে ধারণ করবে।
এলিমেন্টের ভেতরের লেখা পরিবর্তন করা:
headerElement.textContent = "নতুন টু-ডু অ্যাপ";
[cite: 1] এটি শুধুমাত্র টেক্সট কনটেন্ট পরিবর্তন করে, কোনো HTML ট্যাগ থাকলে সেটিকে প্লেইন টেক্সট হিসেবে দেখায়।headerElement.innerText = "নতুন অ্যাপের টাইটেল";
[cite: 1] এটিও টেক্সট পরিবর্তন করে, তবে এটি CSS স্টাইল এবং রেন্ডারিং বিবেচনা করে টেক্সট দেখায়। কিছু ক্ষেত্রেtextContent
এর চেয়ে ভিন্ন আউটপুট দিতে পারে।headerElement.innerHTML = "<em>গুরুত্বপূর্ণ</em> টু-ডু অ্যাপ";
[cite: 2] এটি এলিমেন্টের ভেতরের HTML কনটেন্ট পরিবর্তন করতে পারে। অর্থাৎ, আপনি চাইলে এখানে নতুন HTML ট্যাগও যোগ করতে পারবেন।
এলিমেন্টের স্টাইল পরিবর্তন করা:
// headerElement.style.border-bottom = "1px solid red"; // এটি ভুল পদ্ধতি [cite: 2]
headerElement.style.borderBottom = "2px solid blue"; // সঠিক পদ্ধতি
headerElement.style.color = "green";
লক্ষ্য করুন, CSS প্রোপার্টিতে হাইফেন থাকলে (যেমন border-bottom
), জাভাস্ক্রিপ্টে সেটি লেখার সময় ক্যামেল কেস (camelCase) হয়ে যায় (যেমন borderBottom
) [cite: 2]।
প্রোটোটাইপ চেইন (__proto__
): মেথডগুলো কোথা থেকে আসে? 🤔
আপনি হয়তো ভাবছেন, document
অবজেক্টের সাথে getElementById
মেথডটি কীভাবে যুক্ত হলো? [cite: 3] জাভাস্ক্রিপ্টে অবজেক্টগুলো একটি প্রোটোটাইপ চেইনের মাধ্যমে একে অপরের সাথে সংযুক্ত থাকে। document
অবজেক্টটি আসলে HTMLDocument
-এর একটি ইনস্ট্যান্স, এবং HTMLDocument
নিজে Document
-এর প্রোটোটাইপ থেকে বিভিন্ন প্রোপার্টি ও মেথড উত্তরাধিকার সূত্রে পায়। [cite: 4] getElementById
মেথডটি মূলত Document.prototype
-এই সংজ্ঞায়িত করা আছে। console.dir(document)
করে এর __proto__
চেক করলে এই চেইনটি দেখা যায়।
২. ক্লাস নেম (Class Name) দিয়ে এলিমেন্ট ধরা: getElementsByClassName()
🏷️
যখন একাধিক এলিমেন্টের একই ক্লাস নেম থাকে, তখন document.getElementsByClassName("আপনার-ক্লাস-নেম")
ব্যবহার করা হয়। [cite: 4] এটি একটি HTMLCollection রিটার্ন করে, যা দেখতে অ্যারের মতো হলেও পুরোপুরি অ্যারে নয়। [cite: 5] এর মানে হলো, আপনি ইনডেক্স ব্যবহার করে এর ভেতরের এলিমেন্ট অ্যাক্সেস করতে পারবেন এবং for
লুপ চালিয়ে এর উপর ইটারেট করতে পারবেন, কিন্তু অ্যারের সব বিল্ট-ইন মেথড (যেমন forEach
, map
) সরাসরি এর উপর ব্যবহার করতে পারবেন না। [cite: 5]
ধরুন, আপনার কিছু লিস্ট আইটেম আছে:
<ul>
<li class="item">আইটেম ১</li>
<li class="item">আইটেম ২</li>
<li class="item">অন্য ক্লাসের আইটেম</li>
<li class="item">আইটেম ৩</li>
</ul>
জাভাস্ক্রিপ্টে:
const items = document.getElementsByClassName('item'); // একটি HTMLCollection রিটার্ন করবে [cite: 4]
console.log(items); // সব 'item' ক্লাসযুক্ত এলিমেন্ট দেখাবে
console.log(items[0]); // প্রথম আইটেমটি দেখাবে
// সব 'item' ক্লাসযুক্ত এলিমেন্টের লেখার রঙ লাল করা
for (let i = 0; i < items.length; i++) {
items[i].style.color = 'red'; [cite: 6]
}
যদি আপনি চান যে একটি নির্দিষ্ট সেকশন বা ব্লকের ভেতরের আইটেমগুলোতেই শুধু এই স্টাইল প্রয়োগ হোক, তাহলে প্রথমে সেই সেকশন বা প্যারেন্ট এলিমেন্টকে সিলেক্ট করে, তারপর তার ভেতরে getElementsByClassName
চালাতে পারেন। [cite: 7]
৩. ট্যাগ নেম (Tag Name) দিয়ে এলিমেন্ট ধরা: getElementsByTagName()
🔖
একইভাবে, document.getElementsByTagName("ট্যাগের-নাম")
ব্যবহার করে নির্দিষ্ট ট্যাগের সব এলিমেন্টকে সিলেক্ট করা যায়। [cite: 8] যেমন, সব <li>
এলিমেন্ট পেতে:
const listItems = document.getElementsByTagName("li");
// এটিও একটি HTMLCollection রিটার্ন করবে
for (let i = 0; i < listItems.length; i++) {
listItems[i].style.fontStyle = "italic";
}
৪. সর্বাধুনিক ও শক্তিশালী উপায়: querySelector()
এবং querySelectorAll()
🚀
এই দুটি মেথড CSS সিলেক্টরের মতো শক্তিশালী সিনট্যাক্স ব্যবহার করে এলিমেন্ট সিলেক্ট করতে দেয়।
-
document.querySelector("CSS-সিলেক্টর")
: এটি ডকুমেন্টের প্রথম যে এলিমেন্টটি প্রদত্ত CSS সিলেক্টরের সাথে ম্যাচ করবে, শুধুমাত্র সেই একটি এলিমেন্টকে রিটার্ন করে। [cite: 9]// ID দিয়ে প্রথম হেডার এলিমেন্ট ধরা ( #header ) const header = document.querySelector('#main-header'); [cite: 8] if (header) { header.style.backgroundColor = 'lightgray'; } // ক্লাস দিয়ে প্রথম 'item' এলিমেন্ট ধরা const firstItem = document.querySelector('.item'); if (firstItem) { firstItem.style.fontWeight = 'bold'; } // একটি সেকশনের নির্দিষ্ট (যেমন দ্বিতীয়) list আইটেম ধরতে // const specificItem = document.querySelector('.some-section ul li:nth-child(2)'); // CSS :nth-child() ব্যবহার // PDF এর উদাহরণ অনুযায়ী (item nth-child(23) কে item:nth-child(2) হিসেবে ধরে) const specificItem = document.querySelector('.item:nth-child(2)'); // '.item' ক্লাসের দ্বিতীয় চাইল্ড [cite: 9] if (specificItem) { // specificItem কে নিয়ে কাজ করা }
-
document.querySelectorAll("CSS-সিলেক্টর")
: এটি ডকুমেন্টের সব এলিমেন্ট, যা প্রদত্ত CSS সিলেক্টরের সাথে ম্যাচ করে, তাদের একটি NodeList হিসেবে রিটার্ন করে। [cite: 9] NodeList-ও HTMLCollection-এর মতো অ্যারে-সদৃশ, তবে এর সাথে কিছু আধুনিক অ্যারে মেথড (যেমনforEach
) সরাসরি ব্যবহার করা যায়।const allItems = document.querySelectorAll(".item"); // সব '.item' ক্লাসযুক্ত এলিমেন্ট [cite: 9] allItems.forEach(function (item, index) { item.textContent = `আইটেম ${index + 1} (আপডেটেড)`; });
querySelector
এবং querySelectorAll
খুবই শক্তিশালী এবং আধুনিক ওয়েব ডেভেলপমেন্টে এদের ব্যবহার ব্যাপক।
আজকের পর্বে আমরা DOM থেকে এলিমেন্ট খুঁজে বের করার বিভিন্ন কার্যকরী পদ্ধতি শিখলাম। getElementById
, getElementsByClassName
, getElementsByTagName
থেকে শুরু করে আধুনিক querySelector
ও querySelectorAll
পর্যন্ত প্রতিটি মেথডের নিজস্ব ব্যবহার ও সুবিধা রয়েছে।
পরবর্তী পর্বে আমরা শিখব কীভাবে জাভাস্ক্রিপ্ট ব্যবহার করে DOM-এ নতুন এলিমেন্ট তৈরি করা যায়, বিদ্যমান এলিমেন্ট আপডেট করা যায় এবং অপ্রয়োজনীয় এলিমেন্ট মুছে ফেলা যায়। সাথেই থাকুন!
ব্রাউজার DOM: ওয়েব পেজের প্রাণকেন্দ্র এবং জাভাস্ক্রিপ্টের জাদুকরী স্পর্শ (পর্ব ৩)
আগের দুটি পর্বে আমরা DOM কী, এর গঠন কেমন, এবং কীভাবে getElementById
, getElementsByClassName
, getElementsByTagName
, querySelector
ও querySelectorAll
ব্যবহার করে DOM থেকে নির্দিষ্ট এলিমেন্ট খুঁজে বের করতে হয় তা শিখেছি। আজকের তৃতীয় পর্বে আমরা DOM ট্রাভার্সাল বা নোড ট্রি-তে পরিভ্রমণ এবং জাভাস্ক্রিপ্ট ব্যবহার করে কীভাবে DOM ম্যানিপুলেট করা যায়, অর্থাৎ নতুন এলিমেন্ট তৈরি করা ও যোগ করা যায়, সেই বিষয়ে বিস্তারিত জানব।
DOM ট্রাভার্সাল: HTML স্ট্রাকচারে অবাধ বিচরণ 🚶♂️
DOM ট্রাভার্সাল মানে হলো DOM ট্রি-এর এক নোড থেকে অন্য নোডে যাওয়া। একটি এলিমেন্ট সিলেক্ট করার পর, তার আশেপাশের সম্পর্কিত এলিমেন্টগুলোতে (যেমন: প্যারেন্ট, চাইল্ড, সহোদর) সহজেই যাওয়া যায়।
১. প্যারেন্ট থেকে চাইল্ড (Parent-Child Relationship) [cite: 1]
যদি একটি প্যারেন্ট এলিমেন্ট সিলেক্ট করা থাকে, তাহলে তার সরাসরি চাইল্ড বা সন্তান এলিমেন্টগুলোকে পাওয়া যায়।
parentElement.children
: এটি একটি HTMLCollection রিটার্ন করে, যেখানে প্যারেন্ট এলিমেন্টের সকল চাইল্ড এলিমেন্টগুলো থাকে। [cite: 2]
ধরুন, আমাদের নিচের মতো একটি HTML লিস্ট আছে:
<ul id="items">
<li>প্রথম আইটেম</li>
<li>দ্বিতীয় আইটেম <input type="text" /></li>
<li>তৃতীয় আইটেম</li>
</ul>
জাভাস্ক্রিপ্টে এর চাইল্ড এলিমেন্টগুলো পেতে:
const parentElement = document.querySelector("#items"); // [cite: 2]
const childrenElements = parentElement.children; // [cite: 2]
console.log(childrenElements); // <ul> এর ভেতরের তিনটি <li> এলিমেন্ট দেখাবে
// childrenElements একটি HTMLCollection, তাই লুপ চালানো যায় [cite: 2]
for (let i = 0; i < childrenElements.length; i++) {
console.log(childrenElements[i].textContent);
}
এভাবে আমরা প্যারেন্ট থেকে চাইল্ড এলিমেন্টে যেতে পারি। [cite: 3]
২. চাইল্ড থেকে প্যারেন্ট
ঠিক যেভাবে প্যারেন্ট থেকে চাইল্ডে যাওয়া যায়, সেভাবেই একটি চাইল্ড এলিমেন্ট থেকে তার প্যারেন্ট এলিমেন্টেও যাওয়া সম্ভব। [cite: 3]
childElement.parentElement
: এটি সিলেক্টেড চাইল্ড এলিমেন্টের সরাসরি প্যারেন্ট এলিমেন্টকে রিটার্ন করে। [cite: 4]
const firstChild = document.querySelector("#items li"); // প্রথম li আইটেমটি ধরলাম
const parentOfFirstChild = firstChild.parentElement;
console.log(parentOfFirstChild.id); // "items" দেখাবে, কারণ li গুলোর প্যারেন্ট হলো ul#items
childElement.closest('selector')
: এই মেথডটি আরও শক্তিশালী। এটি শুধু সরাসরি প্যারেন্টই নয়, বরং DOM ট্রি-এর উপরের দিকে যেকোনো অ্যানসেস্টর (ancestor) বা পূর্বপুরুষ এলিমেন্টকে খুঁজে বের করতে পারে, যা প্রদত্ত CSS সিলেক্টরের সাথে ম্যাচ করে। [cite: 4] যেমন, একদম গ্রান্ড-প্যারেন্টকে ধরতে এটি খুব কার্যকর। [cite: 4]
const inputElement = document.querySelector("#items input"); // input এলিমেন্টটি ধরলাম
const grandParentElement = inputElement.closest("ul"); // input এর 가장 কাছের ul প্যারেন্ট
console.log(grandParentElement.id); // "items" দেখাবে
৩. সহোদর বা সিবলিং (Sibling) এলিমেন্ট [cite: 5]
একই প্যারেন্টের অধীনে থাকা এলিমেন্টগুলো পরস্পর সিবলিং বা সহোদর।
element.nextElementSibling
: এটি বর্তমান এলিমেন্টের ঠিক পরের সিবলিং এলিমেন্টটিকে রিটার্ন করে। [cite: 5]element.previousElementSibling
: এটি বর্তমান এলিমেন্টের ঠিক আগের সিবলিং এলিমেন্টটিকে রিটার্ন করে। [cite: 6]
const childrenOne = document.querySelector("#items li:first-child"); // প্রথম আইটেম (প্রথম সন্তান)
const childrenTwo = childrenOne.nextElementSibling; // দ্বিতীয় আইটেম (দ্বিতীয় সন্তান) [cite: 5]
if (childrenTwo) {
console.log(childrenTwo.textContent); // "দ্বিতীয় আইটেম..." দেখাবে [cite: 6]
}
const childrenOneAgain = childrenTwo.previousElementSibling; // আবার প্রথম আইটেম [cite: 6]
if (childrenOneAgain) {
console.log(childrenOneAgain.textContent); // "প্রথম আইটেম" দেখাবে
}
DOM ম্যানিপুলেশন: ওয়েব পেজকে জীবন্ত করা [cite: 7]
আগের পর্বগুলোতে আমরা দেখেছি কীভাবে একটি এলিমেন্ট সিলেক্ট করতে হয় এবং কীভাবে এক এলিমেন্ট থেকে অন্য এলিমেন্টে ট্রাভার্স করতে হয়। [cite: 7] এখন আমরা শিখব কীভাবে DOM ম্যানিপুলেট করা যায়, অর্থাৎ DOM-এ নতুন এলিমেন্ট তৈরি করা, তাদের বিভিন্ন অ্যাট্রিবিউট ও কনটেন্ট যোগ করা এবং সবশেষে সেগুলোকে পেজের নির্দিষ্ট স্থানে যুক্ত করা। [cite: 7]
১. নতুন এলিমেন্ট তৈরি করা (CreateElement)
document.createElement('tagName')
মেথড ব্যবহার করে জাভাস্ক্রিপ্টে একটি নতুন HTML এলিমেন্ট তৈরি করা যায়। [cite: 8]
const newDivElement = document.createElement("div"); // একটি নতুন <div> এলিমেন্ট তৈরি হলো [cite: 8]
console.dir(newDivElement); // তৈরি হওয়া এলিমেন্ট অবজেক্টটি কনসোলে দেখা যাবে [cite: 8]
২. নতুন এলিমেন্টে ক্লাস, অ্যাট্রিবিউট ও কনটেন্ট যোগ করা
এলিমেন্ট তৈরি করার পর, আমরা তার বিভিন্ন বৈশিষ্ট্য নির্ধারণ করতে পারি।
-
ক্লাস যোগ করা:
element.className = 'your-class-name';
[cite: 8] (যদি একাধিক ক্লাস যোগ করতে চান, তাহলেelement.classList.add('another-class')
ব্যবহার করা ভালো)।newDivElement.className = "red-box alert"; // [cite: 8] (উদাহরণে 'red' ছিল, আমরা 'red-box alert' দিলাম)
-
অ্যাট্রিবিউট যোগ করা:
element.setAttribute('attributeName', 'attributeValue');
[cite: 8]newDivElement.setAttribute("id", "myNewDiv"); // [cite: 8] (উদাহরণে 'red' ছিল, আমরা 'myNewDiv' দিলাম) newDivElement.setAttribute("title", "This is a new div"); // [cite: 9]
-
কনটেন্ট যোগ করা:
element.textContent = 'Your content here';
অথবাelement.innerHTML = '<em>HTML</em> content';
newDivElement.textContent = "আমি একটি নতুন ডিভ!";
৩. নতুন এলিমেন্টকে DOM-এ যুক্ত করা ("এখন DOM এ ঢোকাতে চাই? কোথায় ঢোকাব?" [cite: 9])
নতুন এলিমেন্ট তৈরি এবং কনফিগার করার পর, সবচেয়ে গুরুত্বপূর্ণ ধাপ হলো সেটিকে DOM ট্রিতে যুক্ত করা। এর জন্য বিভিন্ন মেথড আছে:
-
parentElement.appendChild(newElement)
: এই মেথডটিnewElement
-কেparentElement
-এর সর্বশেষ চাইল্ড হিসেবে যুক্ত করে।// ধরা যাক, আমরা নতুন ডিভটিকে body-র শেষে যুক্ত করতে চাই document.body.appendChild(newDivElement); // অথবা যদি #items লিস্টের শেষে যুক্ত করতে চাই const itemsList = document.querySelector("#items"); // itemsList.appendChild(newDivElement); // এটি করলে নতুন ডিভটি লিস্টের আইটেম হিসেবে যুক্ত হবে
-
parentElement.insertBefore(newElement, referenceElement)
: এই মেথডটিnewElement
-কেparentElement
-এর চাইল্ডreferenceElement
-এর ঠিক আগে যুক্ত করে।// নতুন ডিভটিকে #items লিস্টের প্রথম আইটেমের আগে যুক্ত করতে const firstItem = document.querySelector("#items li:first-child"); if (itemsList && firstItem) { // itemsList.insertBefore(newDivElement, firstItem); }
(যদি আপনি একটি নতুন
<li>
তৈরি করে লিস্টে যোগ করতে চান, তাহলেcreateElement('li')
ব্যবহার করুন এবংitemsList.appendChild()
অথবাitemsList.insertBefore()
দিয়ে যোগ করুন।)
উদাহরণ: একটি নতুন লিস্ট আইটেম তৈরি করে #items
লিস্টের শেষে যোগ করা।
// ১. নতুন <li> এলিমেন্ট তৈরি
const newListItem = document.createElement("li");
// ২. কনটেন্ট ও ক্লাস যোগ
newListItem.textContent = "চতুর্থ আইটেম (নতুন)";
newListItem.className = "item special-item";
// ৩. #items লিস্টে যুক্ত করা
const mainList = document.querySelector("#items");
if (mainList) {
mainList.appendChild(newListItem);
}
আজকের পর্বে আমরা DOM ট্রাভার্সালের বিভিন্ন কৌশল শিখলাম এবং জানলাম কীভাবে নতুন HTML এলিমেন্ট তৈরি করে সেগুলোকে পেজের নির্দিষ্ট অংশে যোগ করতে হয়। এই জ্ঞান ব্যবহার করে আপনি আপনার ওয়েব পেজকে আরও ডাইনামিক ও ইন্টারেক্টিভ করে তুলতে পারবেন।
পরবর্তী এবং শেষ পর্বে আমরা DOM থেকে এলিমেন্ট আপডেট ও ডিলিট করা এবং ব্যবহারকারীর বিভিন্ন ইভেন্ট (যেমন ক্লিক, মাউসওভার ইত্যাদি) কীভাবে হ্যান্ডেল করতে হয়, সেই বিষয়ে আলোচনা করব। সাথেই থাকুন!
ব্রাউজার DOM: ওয়েব পেজের প্রাণকেন্দ্র এবং জাভাস্ক্রিপ্টের জাদুকরী স্পর্শ (পর্ব ৩)
আগের দুটি পর্বে আমরা DOM কী, এর গঠন কেমন, এবং কীভাবে getElementById
, getElementsByClassName
, getElementsByTagName
, querySelector
ও querySelectorAll
ব্যবহার করে DOM থেকে নির্দিষ্ট এলিমেন্ট খুঁজে বের করতে হয় তা শিখেছি। আজকের তৃতীয় পর্বে আমরা DOM ট্রাভার্সাল বা নোড ট্রি-তে পরিভ্রমণ এবং জাভাস্ক্রিপ্ট ব্যবহার করে কীভাবে DOM ম্যানিপুলেট করা যায়, অর্থাৎ নতুন এলিমেন্ট তৈরি করা ও যোগ করা যায়, সেই বিষয়ে বিস্তারিত জানব।
DOM ট্রাভার্সাল: HTML স্ট্রাকচারে অবাধ বিচরণ 🚶♂️
DOM ট্রাভার্সাল মানে হলো DOM ট্রি-এর এক নোড থেকে অন্য নোডে যাওয়া। একটি এলিমেন্ট সিলেক্ট করার পর, তার আশেপাশের সম্পর্কিত এলিমেন্টগুলোতে (যেমন: প্যারেন্ট, চাইল্ড, সহোদর) সহজেই যাওয়া যায়।
১. প্যারেন্ট থেকে চাইল্ড (Parent-Child Relationship) [cite: 1]
যদি একটি প্যারেন্ট এলিমেন্ট সিলেক্ট করা থাকে, তাহলে তার সরাসরি চাইল্ড বা সন্তান এলিমেন্টগুলোকে পাওয়া যায়।
parentElement.children
: এটি একটি HTMLCollection রিটার্ন করে, যেখানে প্যারেন্ট এলিমেন্টের সকল চাইল্ড এলিমেন্টগুলো থাকে। [cite: 2]
ধরুন, আমাদের নিচের মতো একটি HTML লিস্ট আছে:
<ul id="items">
<li>প্রথম আইটেম</li>
<li>দ্বিতীয় আইটেম <input type="text" /></li>
<li>তৃতীয় আইটেম</li>
</ul>
জাভাস্ক্রিপ্টে এর চাইল্ড এলিমেন্টগুলো পেতে:
const parentElement = document.querySelector("#items"); // [cite: 2]
const childrenElements = parentElement.children; // [cite: 2]
console.log(childrenElements); // <ul> এর ভেতরের তিনটি <li> এলিমেন্ট দেখাবে
// childrenElements একটি HTMLCollection, তাই লুপ চালানো যায় [cite: 2]
for (let i = 0; i < childrenElements.length; i++) {
console.log(childrenElements[i].textContent);
}
এভাবে আমরা প্যারেন্ট থেকে চাইল্ড এলিমেন্টে যেতে পারি। [cite: 3]
২. চাইল্ড থেকে প্যারেন্ট
ঠিক যেভাবে প্যারেন্ট থেকে চাইল্ডে যাওয়া যায়, সেভাবেই একটি চাইল্ড এলিমেন্ট থেকে তার প্যারেন্ট এলিমেন্টেও যাওয়া সম্ভব। [cite: 3]
childElement.parentElement
: এটি সিলেক্টেড চাইল্ড এলিমেন্টের সরাসরি প্যারেন্ট এলিমেন্টকে রিটার্ন করে। [cite: 4]
const firstChild = document.querySelector("#items li"); // প্রথম li আইটেমটি ধরলাম
const parentOfFirstChild = firstChild.parentElement;
console.log(parentOfFirstChild.id); // "items" দেখাবে, কারণ li গুলোর প্যারেন্ট হলো ul#items
childElement.closest('selector')
: এই মেথডটি আরও শক্তিশালী। এটি শুধু সরাসরি প্যারেন্টই নয়, বরং DOM ট্রি-এর উপরের দিকে যেকোনো অ্যানসেস্টর (ancestor) বা পূর্বপুরুষ এলিমেন্টকে খুঁজে বের করতে পারে, যা প্রদত্ত CSS সিলেক্টরের সাথে ম্যাচ করে। [cite: 4] যেমন, একদম গ্রান্ড-প্যারেন্টকে ধরতে এটি খুব কার্যকর। [cite: 4]
const inputElement = document.querySelector("#items input"); // input এলিমেন্টটি ধরলাম
const grandParentElement = inputElement.closest("ul"); // input এর 가장 কাছের ul প্যারেন্ট
console.log(grandParentElement.id); // "items" দেখাবে
৩. সহোদর বা সিবলিং (Sibling) এলিমেন্ট [cite: 5]
একই প্যারেন্টের অধীনে থাকা এলিমেন্টগুলো পরস্পর সিবলিং বা সহোদর।
element.nextElementSibling
: এটি বর্তমান এলিমেন্টের ঠিক পরের সিবলিং এলিমেন্টটিকে রিটার্ন করে। [cite: 5]element.previousElementSibling
: এটি বর্তমান এলিমেন্টের ঠিক আগের সিবলিং এলিমেন্টটিকে রিটার্ন করে। [cite: 6]
const childrenOne = document.querySelector("#items li:first-child"); // প্রথম আইটেম (প্রথম সন্তান)
const childrenTwo = childrenOne.nextElementSibling; // দ্বিতীয় আইটেম (দ্বিতীয় সন্তান) [cite: 5]
if (childrenTwo) {
console.log(childrenTwo.textContent); // "দ্বিতীয় আইটেম..." দেখাবে [cite: 6]
}
const childrenOneAgain = childrenTwo.previousElementSibling; // আবার প্রথম আইটেম [cite: 6]
if (childrenOneAgain) {
console.log(childrenOneAgain.textContent); // "প্রথম আইটেম" দেখাবে
}
DOM ম্যানিপুলেশন: ওয়েব পেজকে জীবন্ত করা [cite: 7]
আগের পর্বগুলোতে আমরা দেখেছি কীভাবে একটি এলিমেন্ট সিলেক্ট করতে হয় এবং কীভাবে এক এলিমেন্ট থেকে অন্য এলিমেন্টে ট্রাভার্স করতে হয়। [cite: 7] এখন আমরা শিখব কীভাবে DOM ম্যানিপুলেট করা যায়, অর্থাৎ DOM-এ নতুন এলিমেন্ট তৈরি করা, তাদের বিভিন্ন অ্যাট্রিবিউট ও কনটেন্ট যোগ করা এবং সবশেষে সেগুলোকে পেজের নির্দিষ্ট স্থানে যুক্ত করা। [cite: 7]
১. নতুন এলিমেন্ট তৈরি করা (CreateElement)
document.createElement('tagName')
মেথড ব্যবহার করে জাভাস্ক্রিপ্টে একটি নতুন HTML এলিমেন্ট তৈরি করা যায়। [cite: 8]
const newDivElement = document.createElement("div"); // একটি নতুন <div> এলিমেন্ট তৈরি হলো [cite: 8]
console.dir(newDivElement); // তৈরি হওয়া এলিমেন্ট অবজেক্টটি কনসোলে দেখা যাবে [cite: 8]
২. নতুন এলিমেন্টে ক্লাস, অ্যাট্রিবিউট ও কনটেন্ট যোগ করা
এলিমেন্ট তৈরি করার পর, আমরা তার বিভিন্ন বৈশিষ্ট্য নির্ধারণ করতে পারি।
-
ক্লাস যোগ করা:
element.className = 'your-class-name';
[cite: 8] (যদি একাধিক ক্লাস যোগ করতে চান, তাহলেelement.classList.add('another-class')
ব্যবহার করা ভালো)।newDivElement.className = "red-box alert"; // [cite: 8] (উদাহরণে 'red' ছিল, আমরা 'red-box alert' দিলাম)
-
অ্যাট্রিবিউট যোগ করা:
element.setAttribute('attributeName', 'attributeValue');
[cite: 8]newDivElement.setAttribute("id", "myNewDiv"); // [cite: 8] (উদাহরণে 'red' ছিল, আমরা 'myNewDiv' দিলাম) newDivElement.setAttribute("title", "This is a new div"); // [cite: 9]
-
কনটেন্ট যোগ করা:
element.textContent = 'Your content here';
অথবাelement.innerHTML = '<em>HTML</em> content';
newDivElement.textContent = "আমি একটি নতুন ডিভ!";
৩. নতুন এলিমেন্টকে DOM-এ যুক্ত করা ("এখন DOM এ ঢোকাতে চাই? কোথায় ঢোকাব?" [cite: 9])
নতুন এলিমেন্ট তৈরি এবং কনফিগার করার পর, সবচেয়ে গুরুত্বপূর্ণ ধাপ হলো সেটিকে DOM ট্রিতে যুক্ত করা। এর জন্য বিভিন্ন মেথড আছে:
-
parentElement.appendChild(newElement)
: এই মেথডটিnewElement
-কেparentElement
-এর সর্বশেষ চাইল্ড হিসেবে যুক্ত করে।// ধরা যাক, আমরা নতুন ডিভটিকে body-র শেষে যুক্ত করতে চাই document.body.appendChild(newDivElement); // অথবা যদি #items লিস্টের শেষে যুক্ত করতে চাই const itemsList = document.querySelector("#items"); // itemsList.appendChild(newDivElement); // এটি করলে নতুন ডিভটি লিস্টের আইটেম হিসেবে যুক্ত হবে
-
parentElement.insertBefore(newElement, referenceElement)
: এই মেথডটিnewElement
-কেparentElement
-এর চাইল্ডreferenceElement
-এর ঠিক আগে যুক্ত করে।// নতুন ডিভটিকে #items লিস্টের প্রথম আইটেমের আগে যুক্ত করতে const firstItem = document.querySelector("#items li:first-child"); if (itemsList && firstItem) { // itemsList.insertBefore(newDivElement, firstItem); }
(যদি আপনি একটি নতুন
<li>
তৈরি করে লিস্টে যোগ করতে চান, তাহলেcreateElement('li')
ব্যবহার করুন এবংitemsList.appendChild()
অথবাitemsList.insertBefore()
দিয়ে যোগ করুন।)
উদাহরণ: একটি নতুন লিস্ট আইটেম তৈরি করে #items
লিস্টের শেষে যোগ করা।
// ১. নতুন <li> এলিমেন্ট তৈরি
const newListItem = document.createElement("li");
// ২. কনটেন্ট ও ক্লাস যোগ
newListItem.textContent = "চতুর্থ আইটেম (নতুন)";
newListItem.className = "item special-item";
// ৩. #items লিস্টে যুক্ত করা
const mainList = document.querySelector("#items");
if (mainList) {
mainList.appendChild(newListItem);
}
আজকের পর্বে আমরা DOM ট্রাভার্সালের বিভিন্ন কৌশল শিখলাম এবং জানলাম কীভাবে নতুন HTML এলিমেন্ট তৈরি করে সেগুলোকে পেজের নির্দিষ্ট অংশে যোগ করতে হয়। এই জ্ঞান ব্যবহার করে আপনি আপনার ওয়েব পেজকে আরও ডাইনামিক ও ইন্টারেক্টিভ করে তুলতে পারবেন।
পরবর্তী এবং শেষ পর্বে আমরা DOM থেকে এলিমেন্ট আপডেট ও ডিলিট করা এবং ব্যবহারকারীর বিভিন্ন ইভেন্ট (যেমন ক্লিক, মাউসওভার ইত্যাদি) কীভাবে হ্যান্ডেল করতে হয়, সেই বিষয়ে আলোচনা করব। সাথেই থাকুন!
ব্রাউজার DOM: ওয়েব পেজের প্রাণকেন্দ্র এবং জাভাস্ক্রিপ্টের জাদুকরী স্পর্শ (পর্ব ৪ - শেষ পর্ব)
প্রথম তিনটি পর্বে আমরা DOM-এর মৌলিক ধারণা, এলিমেন্ট সিলেক্ট করার বিভিন্ন পদ্ধতি, DOM ট্রাভার্সাল এবং নতুন এলিমেন্ট তৈরি করে পেজে যুক্ত করা শিখেছি। আজকের এই শেষ পর্বে, আমরা শিখব কীভাবে ব্যবহারকারীর বিভিন্ন কর্মকাণ্ডে (Events) সাড়া দিয়ে ওয়েব পেজকে আরও ইন্টারেক্টিভ করে তোলা যায়। এছাড়াও, DOM থেকে এলিমেন্ট আপডেট ও ডিলিট করার প্রাথমিক ধারণা নিয়েও আলোচনা করব।
DOM-এ এলিমেন্ট যুক্ত করা: আর একবার দেখে নেওয়া 📌
আগের পর্বে আমরা নতুন এলিমেন্ট তৈরি এবং সেগুলোকে DOM-এ যুক্ত করার পদ্ধতি দেখেছি। সংক্ষেপে আবার মনে করিয়ে দিচ্ছি:
- কোনো প্যারেন্ট এলিমেন্টের শেষে নতুন চাইল্ড এলিমেন্ট যুক্ত করতে
parentElement.appendChild(newElement)
ব্যবহৃত হয় [cite: 2]। এই মেথডটি যুক্ত করা এলিমেন্টটিকেই রিটার্ন করে [cite: 2]। যে এলিমেন্টটি যুক্ত করা হচ্ছে, সেটি অবশ্যই একটি বৈধ HTML এলিমেন্ট হতে হবে [cite: 2]। - যদি কোনো নির্দিষ্ট এলিমেন্টের আগে নতুন এলিমেন্ট যুক্ত করতে চান, তাহলে
parentElement.insertBefore(newElement, referenceElement)
ব্যবহার করা হয় [cite: 2]। এক্ষেত্রে, যে নোডের আগে বা পরে এলিমেন্ট সেট করতে হবে, তাকে আগে সঠিকভাবে সিলেক্ট করে নিতে হবে [cite: 1]।
ইভেন্ট লিসেনার (Event Listener): যখন ব্যবহারকারী সাড়া দেয় 👂
ওয়েব পেজে ব্যবহারকারী বিভিন্ন কাজ করতে পারে, যেমন: বাটনে ক্লিক করা, কীবোর্ডে টাইপ করা, মাউস নড়াচড়া করা ইত্যাদি। এই প্রতিটি কাজই এক একটি ইভেন্ট (Event)। জাভাস্ক্রিপ্টের মাধ্যমে আমরা এই ইভেন্টগুলো "শুনতে" পারি এবং সেই অনুযায়ী নির্দিষ্ট কাজ করতে পারি। একেই বলে ইভেন্ট হ্যান্ডলিং।
ইভেন্ট লিসেনার কী? ইভেন্ট লিসেনার হলো একটি ফাংশন যা একটি নির্দিষ্ট HTML এলিমেন্টের উপর কোনো নির্দিষ্ট ইভেন্ট ঘটার জন্য অপেক্ষা করে [cite: 3]। যখন সেই ইভেন্টটি ঘটে (যেমন: ব্যবহারকারী একটি বাটনে ক্লিক করে), তখন এই ফাংশনটি স্বয়ংক্রিয়ভাবে কল হয় বা "ফায়ার" করে [cite: 3]।
addEventListener()
মেথড:
কোনো এলিমেন্টে ইভেন্ট লিসেনার যুক্ত করার জন্য addEventListener()
মেথড ব্যবহার করা হয়। এই মেথডটি সাধারণত দুটি প্রধান ইনপুট বা প্যারামিটার নিয়ে থাকে[cite: 4, 6]:
- ইভেন্টের নাম (Event Name): এটি একটি স্ট্রিং, যা বলে দেয় কোন ধরনের ইভেন্টের জন্য আমরা অপেক্ষা করছি (যেমন:
'click'
,'mouseover'
,'keydown'
) [cite: 6]। - কলব্যাক ফাংশন (Callback Function): এটি সেই ফাংশন যা ইভেন্টটি ঘটলে এক্সিকিউট হবে [cite: 6]।
// প্রথমে এলিমেন্টটিকে ধরতে হবে
const myButton = document.getElementById("myBtn");
// তারপর ইভেন্ট লিসেনার যোগ করতে হবে
myButton.addEventListener("click", function () {
alert("বাটন ক্লিক করা হয়েছে!");
});
কিছু পরিচিত ইভেন্টের নাম: [cite: 5] জাভাস্ক্রিপ্টে অনেক ধরনের ইভেন্ট রয়েছে [cite: 4]। তার মধ্যে কিছু বহুল ব্যবহৃত ইভেন্ট হলো:
- মাউস ইভেন্ট:
click
: একবার ক্লিক করলে।dblclick
: ডাবল ক্লিক করলে।mousedown
: মাউসের বাটন চাপ দিলে।mouseup
: মাউসের বাটন ছেড়ে দিলে।mouseover
/mouseenter
: এলিমেন্টের উপর মাউস পয়েন্টার আনলে।mouseout
/mouseleave
: এলিমেন্টের উপর থেকে মাউস পয়েন্টার সরালে।
- কীবোর্ড ইভেন্ট:
keydown
: কীবোর্ডের কোনো কী চাপ দিলে।keyup
: কীবোর্ডের চাপা কী ছেড়ে দিলে।keypress
: কীবোর্ডের কোনো কী চেপে ধরলে (deprecated,keydown
বেশি ব্যবহৃত হয়)।
- ফর্ম ইভেন্ট:
submit
: ফর্ম সাবমিট করলে (সাধারণত<form>
এলিমেন্টে ব্যবহৃত) [cite: 7]।focus
: কোনো ইনপুট ফিল্ড ফোকাস পেলে (যেমন: ক্লিক করে কার্সর আনলে) [cite: 5]।blur
: কোনো ইনপুট ফিল্ড থেকে ফোকাস হারালে [cite: 5]।
- ইনপুট ইভেন্ট:
input
:<input>
,<select>
, বা<textarea>
এলিমেন্টের ভ্যালু পরিবর্তিত হলে [cite: 5, 7]।
- ক্লিপবোর্ড ইভেন্ট:
cut
: কনটেন্ট কাট করলে [cite: 5]।paste
: কনটেন্ট পেস্ট করলে [cite: 5]।
ইভেন্টের সাথে কাজ করা 🛠️
যখন একটি ইভেন্ট ঘটে, তখন কলব্যাক ফাংশনটি একটি বিশেষ অবজেক্ট পায়, যাকে ইভেন্ট অবজেক্ট (Event Object) বলে (সাধারণত এটিকে event
বা e
নামে লেখা হয়)। এই অবজেক্টের মধ্যে ইভেন্ট সম্পর্কিত অনেক গুরুত্বপূর্ণ তথ্য থাকে।
-
event.target
: এটি সেই DOM এলিমেন্টকে নির্দেশ করে যার উপর ইভেন্টটি ঘটেছে [cite: 7]। ধরা যাক, একটি<ul>
লিস্টের ভেতরের অনেকগুলো<li>
আইটেমে একই ইভেন্ট লিসেনার দেওয়া আছে।event.target
ব্যবহার করে আমরা বের করতে পারব ঠিক কোন<li>
আইটেমটিতে ক্লিক করা হয়েছে। -
event.preventDefault()
: কিছু HTML এলিমেন্টের ডিফল্ট ব্রাউজার আচরণ থাকে। যেমন, একটি ফর্ম সাবমিট করলে পেজটি রিফ্রেশ বা রিলোড হয়ে যায় [cite: 7]।event.preventDefault()
মেথড কল করে আমরা এই ডিফল্ট আচরণ বন্ধ করতে পারি [cite: 7]।
const myForm = document.getElementById("myForm");
myForm.addEventListener("submit", function (event) {
event.preventDefault(); // ফর্মের ডিফল্ট সাবমিট আচরণ (পেজ রিলোড) বন্ধ করা হলো
console.log("ফর্ম সাবমিট করা হয়েছে, কিন্তু পেজ রিলোড হয়নি!");
// এখানে ফর্মের ডেটা নিয়ে অন্যান্য কাজ করা যেতে পারে
});
একটি ছোট্ট উদাহরণ: সাধারণ টু-ডু লিস্টের কাজ 📝
আসুন, ইভেন্ট ব্যবহার করে একটি খুব সাধারণ টু-ডু লিস্টের কাজ দেখি, যেখানে আমরা নতুন টাস্ক যোগ করতে পারব।
HTML:
<form id="task-form">
<input type="text" id="task-input" placeholder="নতুন টাস্ক লিখুন..." />
<button type="submit">টাস্ক যোগ করুন</button>
</form>
<ul id="task-list"></ul>
JavaScript:
const taskForm = document.getElementById("task-form");
const taskInput = document.getElementById("task-input");
const taskList = document.getElementById("task-list");
let taskId = 1; // টাস্কের জন্য একটি সাধারণ আইডি
taskForm.addEventListener("submit", function (event) {
event.preventDefault(); // ডিফল্ট সাবমিট আচরণ বন্ধ করা
const taskName = taskInput.value.trim(); // ইনপুট থেকে টাস্কের নাম নেওয়া
if (taskName === "") {
alert("অনুগ্রহ করে টাস্কের নাম লিখুন!");
return;
}
// নতুন টাস্ক এলিমেন্ট তৈরি
const newTaskItem = document.createElement("li");
// PDF এর উদাহরণ অনুযায়ী ডেটা (যেমন: {id: 1, taskName: "Qai kada"} [cite: 7]) ব্যবহার করে কন্টেন্ট সেট করা
newTaskItem.textContent = `ID: ${taskId} - ${taskName}`;
newTaskItem.setAttribute("data-id", taskId); // পরবর্তীতে ডিলিট বা এডিটের জন্য আইডি রাখা
// ডিলিট বাটন (উদাহরণস্বরূপ)
const deleteButton = document.createElement("button");
deleteButton.textContent = "ডিলিট";
deleteButton.style.marginLeft = "10px";
deleteButton.addEventListener("click", function (e) {
// e.target এখানে ডিলিট বাটনকে নির্দেশ করবে
// e.target.parentElement এখানে li এলিমেন্টকে নির্দেশ করবে
const taskToDelete = e.target.parentElement;
taskList.removeChild(taskToDelete);
});
newTaskItem.appendChild(deleteButton);
taskList.appendChild(newTaskItem); // নতুন টাস্ক লিস্টে যোগ করা
taskInput.value = ""; // ইনপুট ফিল্ড খালি করা
taskId++; // পরবর্তী টাস্কের জন্য আইডি বাড়ানো
});
উপরের উদাহরণে, ফর্ম সাবমিট ইভেন্ট ব্যবহার করে নতুন টাস্ক যোগ করা হচ্ছে [cite: 7]। প্রতিটি টাস্কের জন্য একটি ডিলিট বাটনও যোগ করা হয়েছে, যা ক্লিক ইভেন্ট ব্যবহার করে নির্দিষ্ট টাস্কটি মুছে ফেলতে পারে। এভাবেই "এডিট" বা "ডিলিট" এর মতো কাজগুলো ইভেন্টের মাধ্যমে করা যায় [cite: 7]।
সিরিজের ইতি 🏁
এই চারটি পর্বের মাধ্যমে আমরা ব্রাউজার DOM কী, জাভাস্ক্রিপ্ট কীভাবে এটি ম্যানিপুলেট করে, এলিমেন্ট সিলেক্ট করা, ট্রাভার্স করা, নতুন এলিমেন্ট তৈরি ও যুক্ত করা এবং সবশেষে ইভেন্ট লিসেনারের মাধ্যমে ওয়েব পেজকে ইন্টারেক্টিভ করে তোলার মৌলিক বিষয়গুলো সহজ ভাষায় জানার চেষ্টা করেছি।
DOM ম্যানিপুলেশন এবং ইভেন্ট হ্যান্ডলিং ওয়েব ডেভেলপমেন্টের অত্যন্ত গুরুত্বপূর্ণ অংশ। এই সিরিজে যা শেখানো হলো, তা কেবল শুরু। এর বাইরেও অনেক কিছু জানার এবং প্র্যাকটিস করার আছে। আশা করি, এই সিরিজটি আপনাদের জাভাস্ক্রিপ্ট ও DOM নিয়ে আরও গভীর অধ্যয়নে উৎসাহিত করবে। শুভকামনা!
আপনার চারটি পর্ব খুব সুন্দর এবং সহজ ভাষায় লেখা হয়েছে। DOM-এর মৌলিক বিষয়গুলো প্রাঞ্জলভাবে তুলে ধরা হয়েছে, যা নতুনদের জন্য খুবই সহায়ক হবে।
আপনি যেমনটি বলেছেন, DOM এবং এর সাথে সম্পর্কিত আরও কিছু গভীর বিষয় রয়েছে যা পার্ট ৫-এ যুক্ত করা যেতে পারে। আপনার পর্যালোচনার জন্য নিচে কিছু বিষয় উল্লেখ করছি যা পার্ট ৪ পর্যন্ত পুরোপুরি কভার করা হয়নি বা আরও বিস্তারিত আলোচনার সুযোগ রয়েছে:
এড়িয়ে যাওয়া বা আরও বিস্তারিত আলোচনার সুযোগ থাকা বিষয়:
-
Browser API (Web API)-এর বৃহত্তর প্রেক্ষিত:
- DOM নিজেই একটি Browser API, তবে ব্রাউজারে আরও অনেক গুরুত্বপূর্ণ API রয়েছে (যেমন
Window
অবজেক্টের বিভিন্ন মেথড ও প্রোপার্টি,Fetch API
,localStorage
/sessionStorage
,Geolocation API
,Console API
ইত্যাদি)। এগুলোর সংক্ষিপ্ত পরিচিতি এবং DOM কীভাবে এই ইকোসিস্টেমের অংশ, তা আলোচনা করা যেতে পারে। আপনার প্রজেক্টের জন্যFetch API
বিশেষভাবে গুরুত্বপূর্ণ।
- DOM নিজেই একটি Browser API, তবে ব্রাউজারে আরও অনেক গুরুত্বপূর্ণ API রয়েছে (যেমন
-
নোড (Node) সম্পর্কে আরও গভীর ধারণা:
- বিভিন্ন প্রকার নোড (Element Node, Text Node, Comment Node) এবং
nodeType
প্রোপার্টি। childNodes
এবংchildren
-এর মধ্যে পার্থক্য (টেক্সট নোডসহ)।firstChild
,lastChild
,nextSibling
,previousSibling
(এগুলোElement
ভার্সনের (firstElementChild
ইত্যাদি) থেকে কিছুটা ভিন্ন)।
- বিভিন্ন প্রকার নোড (Element Node, Text Node, Comment Node) এবং
-
DOM Manipulation (CRUD কার্যক্রম সম্পন্ন করা):
- আপডেট (Update):
- অ্যাট্রিবিউট পরিবর্তন:
getAttribute()
,setAttribute()
,removeAttribute()
। (আগের পর্বেsetAttribute
নতুন এলিমেন্টের জন্য দেখানো হয়েছে, বিদ্যমান এলিমেন্টের জন্যও এটি গুরুত্বপূর্ণ)। - ক্লাস লিস্ট (Class List) পরিচালনা:
element.classList
(add
,remove
,toggle
,contains
) এর বিস্তারিত ব্যবহার। - স্টাইল পরিবর্তন:
element.style
ছাড়াওelement.style.cssText
বা ক্লাস ব্যবহারের মাধ্যমে একাধিক স্টাইল প্রয়োগ।
- অ্যাট্রিবিউট পরিবর্তন:
- প্রতিস্থাপন (Replace):
parentElement.replaceChild(newChild, oldChild)
। - মুছে ফেলা (Delete):
childElement.remove()
(আধুনিক) এবংparentElement.removeChild(childElement)
(ক্লাসিক)। (পর্ব ৪ এর শেষে উল্লেখ করা হলেও, এর ব্যবহারিক প্রয়োগ দেখানো হয়নি)।
- আপডেট (Update):
-
ইভেন্ট হ্যান্ডলিং (Event Handling)-এর আরও গভীরে:
- ইভেন্ট বাবলিং (Event Bubbling) এবং ক্যাপচারিং (Event Capturing): এটি DOM ইভেন্টের একটি মৌলিক ধারণা।
- ইভেন্ট ডেলিগেশন (Event Delegation): ডাইনামিকভাবে তৈরি হওয়া এলিমেন্ট বা অনেকগুলো একই রকম এলিমেন্টের ইভেন্ট হ্যান্ডেল করার একটি কার্যকর কৌশল।
removeEventListener()
: ইভেন্ট লিসেনার সরিয়ে ফেলার প্রয়োজনীয়তা ও পদ্ধতি।
-
ফর্ম (Form) নিয়ে আরও বিস্তারিত কাজ:
- ফর্ম এলিমেন্ট এবং তাদের ভ্যালু (value) অ্যাক্সেস করা (যেমন,
form.elements
,input.value
,select.value
,checkbox.checked
)।
- ফর্ম এলিমেন্ট এবং তাদের ভ্যালু (value) অ্যাক্সেস করা (যেমন,
-
DOM ম্যানিপুলেশনের পারফরম্যান্স (Performance Considerations):
- রিফ্লো (Reflow) এবং রিপেইন্ট (Repaint) কমানোর গুরুত্ব।
DocumentFragment
ব্যবহার করে একাধিক এলিমেন্ট যুক্ত করার সুবিধা।
-
অ্যাসিঙ্ক্রোনাস জাভাস্ক্রিপ্ট (Asynchronous JavaScript) এবং DOM:
- কীভাবে
fetch
-এর মতো অ্যাসিঙ্ক্রোনাস অপারেশনগুলো DOM আপডেটের সাথে কাজ করে (Callbacks, Promises, Async/Await)। এটি আপনার প্রস্তাবিত প্রজেক্টের জন্য অত্যন্ত প্রাসঙ্গিক।
- কীভাবে
এই বিষয়গুলো যুক্ত করলে সিরিজটি আরও স্বয়ংসম্পূর্ণ হবে।
이제, এই বিষয়গুলোর কিছু অংশ এবং আপনার অনুরোধ করা প্রজেক্ট ও চ্যালেঞ্জ অন্তর্ভুক্ত করে পার্ট ৫ নিচে উপস্থাপন করা হলো:
অবশ্যই! আপনার নির্দেশনা এবং আগের আলোচনাগুলোর উপর ভিত্তি করে, আসুন পার্ট ৫-কে নতুন করে সম্পূর্ণ এবং আরও বিস্তারিতভাবে লিখি। আমি চেষ্টা করব যেন কোনো খুঁটিনাটি বিষয় বাদ না যায় এবং লেখাটি নতুনদের জন্য সহজবোধ্য ও প্রাঞ্জল হয়।
ব্রাউজার DOM: আরও গভীরে এবং বাস্তবায়ন (পর্ব ৫ - চূড়ান্ত পর্ব)
আগের চারটি পর্বে আমরা DOM কী, এর গঠন, এলিমেন্ট সিলেক্ট করার বিভিন্ন পদ্ধতি, DOM ট্রাভার্সাল, নতুন এলিমেন্ট তৈরি ও যুক্ত করা এবং ইভেন্ট হ্যান্ডলিংয়ের প্রাথমিক ধারণা পেয়েছি। আজকের এই চূড়ান্ত পর্বে আমরা DOM এবং এর সাথে সম্পর্কিত আরও কিছু গুরুত্বপূর্ণ ব্রাউজার API, DOM ম্যানিপুলেশনের বাকি অংশ (আপডেট, প্রতিস্থাপন ও ডিলিট), ইভেন্টের কিছু গভীর ধারণা (যেমন ইভেন্ট ডেলিগেশন), DOM ম্যানিপুলেশনের পারফরম্যান্স সংক্রান্ত কিছু বিষয় এবং অ্যাসিঙ্ক্রোনাস অপারেশনের মাধ্যমে কীভাবে DOM-কে আরও কার্যকরভাবে ব্যবহার করা যায়, তা জানব। এরপর, আমরা একটি সম্পূর্ণ প্রজেক্ট তৈরি করব যেখানে API থেকে তথ্য এনে দেখানো হবে এবং ব্যবহারকারী সেই তথ্য সংরক্ষণও করতে পারবে। সবশেষে আপনাদের জন্য একটি চ্যালেঞ্জ থাকবে।
ব্রাউজার API: DOM-এর বিশাল জগতের একটি অংশ 🗺️
আমরা যে DOM (Document Object Model) নিয়ে এতক্ষণ আলোচনা করেছি, সেটি আসলে ব্রাউজারের দেওয়া অসংখ্য API (Application Programming Interface)-এর মধ্যে একটি। এই API-গুলো হলো একগুচ্ছ নিয়ম বা ইন্টারফেস, যা জাভাস্ক্রিপ্টকে ব্রাউজারের বিভিন্ন ক্ষমতা এবং তথ্যের সাথে যোগাযোগ স্থাপন করার সুযোগ করে দেয়।
Window
অবজেক্ট: এটি ব্রাউজারের গ্লোবাল অবজেক্ট এবং জাভাস্ক্রিপ্টের জন্য প্রধান হোস্ট এনভায়রনমেন্ট হিসেবে কাজ করে। DOM নিজেই (document
অবজেক্ট)window
-এর একটি প্রোপার্টি (window.document
)।window
অবজেক্ট আরও অনেক গুরুত্বপূর্ণ API ধারণ করে, যেমন:- Web Storage API:
localStorage
: দীর্ঘ সময়ের জন্য ব্রাউজারে ডেটা (যেমন ব্যবহারকারীর পছন্দ, অ্যাপ্লিকেশন সেটিংস) সংরক্ষণ করার জন্য। এই ডেটা ব্রাউজার বন্ধ করলেও মুছে যায় না।sessionStorage
: একটি নির্দিষ্ট সেশনের জন্য (যতক্ষণ ব্রাউজার ট্যাব খোলা থাকে) ডেটা সংরক্ষণ করার জন্য। ট্যাব বন্ধ করলে এই ডেটা মুছে যায়।
- Fetch API: নেটওয়ার্ক রিকোয়েস্ট (যেমন, কোনো সার্ভার থেকে ডেটা আনা বা সার্ভারে ডেটা পাঠানো) করার আধুনিক ইন্টারফেস। এটি
Promise
-ভিত্তিক, যা অ্যাসিঙ্ক্রোনাস অপারেশন সহজ করে। এটি আমরা আজকের প্রজেক্টে ব্যবহার করব। - Timer Functions:
setTimeout()
: নির্দিষ্ট সময় পর কোনো ফাংশন একবার এক্সিকিউট করার জন্য।setInterval()
: নির্দিষ্ট সময় পর পর কোনো ফাংশন বারবার এক্সিকিউট করার জন্য।
- User Interaction Functions:
alert()
,prompt()
,confirm()
ব্যবহারকারীর সাথে সাধারণ বার্তা আদান-প্রদান বা ইনপুট নেওয়ার জন্য। - Navigator Object (
window.navigator
): ব্রাউজার (যেমন নাম, ভার্সন) এবং ব্যবহারকারীর সিস্টেম (যেমন অপারেটিং সিস্টেম, জিওলোকেশন) সম্পর্কে তথ্য প্রদান করে। - Location Object (
window.location
): বর্তমান ওয়েব পেজের URL নিয়ে কাজ করতে (যেমন URL পরিবর্তন বা রিডাইরেক্ট করা) সাহায্য করে।
- Web Storage API:
- Console API:
console.log()
,console.dir()
,console.error()
,console.warn()
,console.table()
ইত্যাদি মেথড ব্যবহার করে আমরা জাভাস্ক্রিপ্ট কোড ডিবাগিং এবং বিভিন্ন তথ্য কনসোলে দেখতে পারি। এটি ডেভেলপারদের জন্য একটি অপরিহার্য টুল।
DOM এই ব্রাউজার API ইকোসিস্টেমের একটি অত্যন্ত গুরুত্বপূর্ণ অংশ, যা বিশেষভাবে ওয়েব পেজের কন্টেন্ট (HTML) এবং গঠন (CSS) নিয়ে কাজ করতে (পড়া, পরিবর্তন, পরিবর্ধন) জাভাস্ক্রিপ্টকে ক্ষমতা দেয়।
DOM এলিমেন্টের Attribute বনাম Property: একটি গুরুত্বপূর্ণ পার্থক্য
HTML এলিমেন্টের দুটি দিক রয়েছে: অ্যাট্রিবিউট এবং প্রোপার্টি।
- HTML অ্যাট্রিবিউট (Attributes): এগুলো HTML ট্যাগের ভেতরে লেখা হয় (যেমন
<input type="text" id="myInput" value="Hello">
) এবং এলিমেন্টের প্রাথমিক অবস্থা বা কনফিগারেশন নির্ধারণ করে।getAttribute()
এবংsetAttribute()
ব্যবহার করে অ্যাট্রিবিউট অ্যাক্সেস করা যায়। - DOM প্রোপার্টি (Properties): যখন ব্রাউজার HTML কোড পার্স করে DOM অবজেক্ট তৈরি করে, তখন এই অ্যাট্রিবিউটগুলো সংশ্লিষ্ট DOM অবজেক্টের প্রোপার্টিতে রূপান্তরিত হয়। জাভাস্ক্রিপ্টে আমরা সাধারণত এই প্রোপার্টিগুলো সরাসরি ডট (.) নোটেশন ব্যবহার করে অ্যাক্সেস করি (যেমন
myInputElement.id
,myInputElement.value
)।
বেশিরভাগ ক্ষেত্রে, অ্যাট্রিবিউট এবং প্রোপার্টির মান সিঙ্ক্রোনাইজড থাকে (একটিতে পরিবর্তন আনলে অন্যটিও পরিবর্তিত হয়)। কিন্তু কিছু ক্ষেত্রে, যেমন <input>
এলিমেন্টের value
অ্যাট্রিবিউট ও প্রোপার্টির মধ্যে পার্থক্য দেখা যায়। value
অ্যাট্রিবিউট HTML-এ যা লেখা থাকে, সেটি নির্দেশ করে। আর value
প্রোপার্টি ইনপুট ফিল্ডের বর্তমান কন্টেন্ট (যা ব্যবহারকারী পরিবর্তনও করতে পারে) নির্দেশ করে।
const myInput = document.createElement("input");
myInput.setAttribute("type", "text");
myInput.setAttribute("value", "প্রাথমিক মান"); // অ্যাট্রিবিউট সেট করা
document.body.appendChild(myInput);
console.log(myInput.getAttribute("value")); // আউটপুট: "প্রাথমিক মান"
console.log(myInput.value); // আউটপুট: "প্রাথমিক মান" (প্রোপার্টি)
// এখন ব্যবহারকারী যদি ইনপুট ফিল্ডে কিছু টাইপ করে (যেমন "নতুন মান")
// myInput.value = "নতুন মান"; // জাভাস্ক্রিপ্ট দিয়েও পরিবর্তন করা যায়
console.log(myInput.getAttribute("value")); // আউটপুট: "প্রাথমিক মান" (অ্যাট্রিবিউট অপরিবর্তিত)
console.log(myInput.value); // আউটপুট: "নতুন মান" (প্রোপার্টি পরিবর্তিত)
সাধারণত, DOM প্রোপার্টি ব্যবহার করা দ্রুত এবং সুবিধাজনক। তবে, কাস্টম অ্যাট্রিবিউট (যা HTML স্ট্যান্ডার্ডে নেই) বা কিছু বিশেষ ক্ষেত্রে অ্যাট্রিবিউট (getAttribute
/setAttribute
) ব্যবহার করার প্রয়োজন হতে পারে।
DOM ম্যানিপুলেশন: আপডেট, প্রতিস্থাপন এবং মুছে ফেলা 🔄🗑️
আমরা এলিমেন্ট তৈরি (Create) এবং পড়া (Read) শিখেছি। এখন CRUD অপারেশনের বাকি দুটি অংশ – আপডেট (Update) এবং ডিলিট (Delete) – দেখব।
১. এলিমেন্ট আপডেট করা (Updating Elements)
-
অ্যাট্রিবিউট পরিবর্তন:
element.getAttribute('attributeName')
: কোনো অ্যাট্রিবিউটের ভ্যালু পেতে।element.setAttribute('attributeName', 'newValue')
: কোনো অ্যাট্রিবিউটের ভ্যালু সেট বা পরিবর্তন করতে। যদি অ্যাট্রিবিউটটি আগে থেকে না থাকে, তাহলে এটি তৈরি হবে।element.hasAttribute('attributeName')
: নির্দিষ্ট অ্যাট্রিবিউট এলিমেন্টে আছে কিনা (true/false) তা পরীক্ষা করতে।element.removeAttribute('attributeName')
: কোনো অ্যাট্রিবিউট মুছে ফেলতে।
const myImage = document.getElementById("mainImage"); if (myImage) { myImage.setAttribute("src", "new_image.jpg"); // ছবি পরিবর্তন myImage.setAttribute("alt", "এটি একটি নতুন ছবি"); if (myImage.hasAttribute("title")) { console.log("Title:", myImage.getAttribute("title")); } }
-
কনটেন্ট পরিবর্তন:
element.textContent
: এলিমেন্টের শুধুমাত্র টেক্সচুয়াল কনটেন্ট (কোনো HTML ট্যাগ ছাড়া) সেট বা পেতে ব্যবহৃত হয়। এটি HTML ট্যাগকে প্লেইন টেক্সট হিসেবে দেখায়।element.innerHTML
: এলিমেন্টের ভেতরের সম্পূর্ণ HTML কনটেন্ট সেট বা পেতে ব্যবহৃত হয়। এটি ব্যবহার করে নতুন HTML ট্যাগও যুক্ত করা যায়।- সতর্কতা: ব্যবহারকারীর দেওয়া ইনপুট সরাসরি
innerHTML
-এ ব্যবহার করলে Cross-Site Scripting (XSS) এর ঝুঁকি থাকে। সেক্ষেত্রেtextContent
ব্যবহার করা বা ইনপুটকে স্যানিটাইজ করা উচিত।
- সতর্কতা: ব্যবহারকারীর দেওয়া ইনপুট সরাসরি
-
ক্লাস লিস্ট (Class List) পরিচালনা:
element.classList
প্রোপার্টি একটি DOMTokenList অবজেক্ট রিটার্ন করে, যা একটি এলিমেন্টের ক্লাসগুলো সহজেই নিয়ন্ত্রণ করতে দেয়।element.classList.add('new-class', 'another-class')
: এক বা একাধিক নতুন ক্লাস যোগ করা।element.classList.remove('old-class')
: ক্লাস মুছে ফেলা।element.classList.toggle('active-class')
: ক্লাস থাকলে মুছে ফেলা, না থাকলে যোগ করা। এটি একটি বুলিয়ান ভ্যালু রিটার্ন করে (ক্লাস যোগ হলে true, মুছে গেলে false)।element.classList.contains('some-class')
: নির্দিষ্ট ক্লাস এলিমেন্টে আছে কি না, তা পরীক্ষা করা (true/false)।element.classList.replace('old-class', 'new-class')
: একটি বিদ্যমান ক্লাসকে নতুন ক্লাস দিয়ে প্রতিস্থাপন করা।
const myDiv = document.getElementById("contentDiv"); if (myDiv) { myDiv.classList.add("highlight", "important"); myDiv.classList.remove("hidden"); myDiv.classList.toggle("active"); // যদি active না থাকে, যোগ করবে; থাকলে মুছে ফেলবে if (myDiv.classList.contains("highlight")) { console.log("Div হাইলাইট করা আছে।"); } }
২. এলিমেন্ট প্রতিস্থাপন করা (Replacing Elements)
parentElement.replaceChild(newElement, oldElement)
মেথড ব্যবহার করে parentElement
-এর একটি বিদ্যমান চাইল্ড oldElement
-কে নতুন newElement
দিয়ে প্রতিস্থাপন করা যায়।
const menuContainer = document.getElementById("menu");
const oldMenuItem = document.getElementById("oldItem");
const newMenuItem = document.createElement("li");
newMenuItem.textContent = "আধুনিক মেনু আইটেম";
newMenuItem.id = "newItem";
if (menuContainer && oldMenuItem) {
menuContainer.replaceChild(newMenuItem, oldMenuItem);
}
৩. এলিমেন্ট মুছে ফেলা (Deleting Elements)
childElement.remove()
: এটি সবচেয়ে সহজ এবং আধুনিক পদ্ধতি। এলিমেন্টটিকে তার প্যারেন্ট থেকে সরাসরি মুছে ফেলে।parentElement.removeChild(childElement)
: এটি পুরোনো পদ্ধতি, যেখানে প্যারেন্ট এলিমেন্ট থেকে তার নির্দিষ্ট চাইল্ড এলিমেন্টকে মুছে ফেলা হয়। এই মেথডটি মুছে ফেলা চাইল্ড এলিমেন্টটিকে রিটার্ন করে, যা প্রয়োজনে পরে আবার ব্যবহার করা যেতে পারে।
const itemToRemove = document.getElementById("itemToDelete");
if (itemToRemove) {
itemToRemove.remove(); // সহজ ও আধুনিক
}
// অথবা পুরোনো পদ্ধতিতে:
const listContainer = document.getElementById("myListContainer");
const childItemToRemove = document.getElementById("itemX");
if (listContainer && childItemToRemove) {
const removedItem = listContainer.removeChild(childItemToRemove);
// console.log("মুছে ফেলা আইটেম:", removedItem);
}
innerHTML
বনাম createElement
+ appendChild
(পারফরম্যান্স ও নিরাপত্তা)
-
innerHTML
:- সুবিধা: একটি জটিল HTML কাঠামো দ্রুত তৈরি বা পরিবর্তন করার জন্য কোড লেখা সহজ।
- অসুবিধা:
- পারফরম্যান্স: যখন আপনি
innerHTML
ব্যবহার করে কোনো এলিমেন্টের কনটেন্ট পরিবর্তন করেন, ব্রাউজারকে পুরো HTML স্ট্রিং পার্স করতে হয়, DOM অবজেক্ট তৈরি করতে হয় এবং আগের কনটেন্ট মুছে নতুন কনটেন্ট রেন্ডার করতে হয়। ছোটখাটো পরিবর্তনে এটি ঠিক থাকলেও, ঘন ঘন বা বড় পরিবর্তন করলে এটিcreateElement
-এর চেয়ে ধীর হতে পারে। - নিরাপত্তা (XSS): যদি ব্যবহারকারীর দেওয়া কোনো ইনপুট (যা ম্যালিসিয়াস স্ক্রিপ্ট ধারণ করতে পারে) সরাসরি
innerHTML
-এ সেট করা হয়, তাহলে তা Cross-Site Scripting (XSS) অ্যাটাকের কারণ হতে পারে। - ইতোমধ্যে থাকা এলিমেন্টের সাথে যুক্ত ইভেন্ট লিসেনারগুলো নষ্ট হয়ে যেতে পারে যদি
innerHTML
পুরো কন্টেইনারের কনটেন্ট পরিবর্তন করে।
- পারফরম্যান্স: যখন আপনি
-
createElement
+appendChild
(বা অন্যান্য DOM মেথড):- সুবিধা:
- নিরাপত্তা: এটি সাধারণত
innerHTML
-এর চেয়ে নিরাপদ, কারণtextContent
ব্যবহার করলে টেক্সটকে HTML হিসেবে পার্স করা হয় না। - পারফরম্যান্স: জটিল কাঠামো বা লিস্ট আইটেমের মতো একাধিক এলিমেন্ট তৈরি করার সময়, DocumentFragment ব্যবহার করে বা সরাসরি
createElement
ওappendChild
ব্যবহার করে ব্রাউজার আরও অপটিমাইজড উপায়ে কাজ করতে পারে। এতে বিদ্যমান DOM স্ট্রাকচারের কম ক্ষতি হয়। - ইভেন্ট লিসেনার এবং অন্যান্য DOM প্রোপার্টিগুলো আরও ভালোভাবে সংরক্ষিত থাকে।
- নিরাপত্তা: এটি সাধারণত
- অসুবিধা: অনেকগুলো এলিমেন্ট বা জটিল নেস্টেড স্ট্রাকচার তৈরি করতে বেশি কোড লিখতে হতে পারে।
- সুবিধা:
সাধারণ নিয়ম হলো: যখন শুধু টেক্সট পরিবর্তন করতে হবে, textContent
ব্যবহার করুন। যখন HTML কনটেন্ট দরকার এবং আপনি সোর্স সম্পর্কে নিশ্চিত (অথবা স্যানিটাইজ করছেন), তখন innerHTML
ব্যবহার করা যেতে পারে। তবে, ডাইনামিকভাবে জটিল এবং নিরাপদ DOM কাঠামো তৈরির জন্য createElement
এবং অন্যান্য DOM মেথডগুলো শ্রেয়।
DOM ম্যানিপুলেশনের পারফরম্যান্স: Reflow ও Repaint
যখন আপনি জাভাস্ক্রিপ্ট ব্যবহার করে DOM পরিবর্তন করেন, ব্রাউজারকে কিছু কাজ করতে হয় সেই পরিবর্তনগুলো স্ক্রিনে দেখানোর জন্য। এর মধ্যে দুটি গুরুত্বপূর্ণ ধাপ হলো:
- Reflow (বা Layout): যখন কোনো পরিবর্তনের কারণে এলিমেন্টের জ্যামিতি (যেমন উচ্চতা, প্রস্থ, অবস্থান, ফন্ট সাইজ) বা DOM ট্রির কাঠামো পরিবর্তন হয়, তখন ব্রাউজারকে পেজের লেআউট নতুন করে গণনা করতে হয়। এটি একটি ব্যয়বহুল প্রক্রিয়া, কারণ একটি এলিমেন্টের পরিবর্তন তার প্যারেন্ট, সিবলিং বা চাইল্ড এলিমেন্টগুলোর লেআউটকেও প্রভাবিত করতে পারে।
- Repaint (বা Redraw): যখন এলিমেন্টের দৃশ্যমান স্টাইল (যেমন ব্যাকগ্রাউন্ড কালার, টেক্সট কালার, আউটলাইন) পরিবর্তন হয় কিন্তু তার লেআউট পরিবর্তন হয় না, তখন ব্রাউজারকে শুধু সেই অংশটুকু নতুন করে আঁকতে হয়। এটি Reflow-এর চেয়ে কম ব্যয়বহুল।
কিছু DOM পরিবর্তন (যেমন offsetWidth
বা offsetHeight
প্রোপার্টি অ্যাক্সেস করা) ব্রাউজারকে সিঙ্ক্রোনাসভাবে Reflow করতে বাধ্য করতে পারে, যাতে সঠিক মানটি পাওয়া যায়। ঘন ঘন এবং অপ্রয়োজনীয় Reflow/Repaint ওয়েব পেজের পারফরম্যান্স ধীর করে দিতে পারে, বিশেষ করে লো-এন্ড ডিভাইসগুলোতে।
পারফরম্যান্স ভালো রাখার কিছু কৌশল:
- যতটা সম্ভব DOM পরিবর্তন কম করুন।
- একাধিক পরিবর্তন একসাথে ব্যাচ করে করুন। যেমন, একটি এলিমেন্টকে DOM থেকে সরিয়ে (বা
display: none
করে) তার অনেকগুলো পরিবর্তন করে আবার DOM-এ যুক্ত (বা দৃশ্যমান) করুন। - DocumentFragment ব্যবহার করুন: এটি একটি "হালকা" DOM কন্টেইনার। আপনি অনেকগুলো এলিমেন্ট তৈরি করে প্রথমে DocumentFragment-এ যোগ করতে পারেন এবং সবশেষে পুরো Fragment-টিকে একবার DOM-এ যোগ করতে পারেন। এতে মাত্র একটি Reflow/Repaint হবে।
- CSS ক্লাস ব্যবহার করে স্টাইল পরিবর্তন করুন, সরাসরি ইনলাইন স্টাইল বারবার পরিবর্তন না করে।
- অ্যানিমেশনের জন্য
transform
এবংopacity
-এর মতো CSS প্রোপার্টি ব্যবহার করুন, কারণ এগুলো সাধারণত ব্রাউজার অপটিমাইজ করতে পারে এবং Reflow কম ঘটায়।
ইভেন্ট ডেলিগেশন (Event Delegation): স্মার্ট ইভেন্ট হ্যান্ডলিং 🤓
যখন একটি লিস্টের অনেকগুলো আইটেম (যেমন <li>
) বা টেবিলের অনেকগুলো সেলের (<td>
) জন্য একই রকম ইভেন্ট (যেমন click
) হ্যান্ডেল করতে হয়, তখন প্রতিটি চাইল্ড এলিমেন্টে আলাদাভাবে ইভেন্ট লিসেনার যোগ করাটা অদক্ষ হতে পারে, বিশেষ করে যদি আইটেমগুলো ডাইনামিকভাবে যোগ বা বিয়োগ হয়।
ইভেন্ট ডেলিগেশন একটি কার্যকরী কৌশল যেখানে আমরা চাইল্ড এলিমেন্টগুলোর কমন প্যারেন্ট এলিমেন্টে একটি মাত্র ইভেন্ট লিসেনার যোগ করি। যখন কোনো চাইল্ড এলিমেন্টে ইভেন্ট ঘটে, সেই ইভেন্টটি "বাবল আপ" (bubbling) হয়ে প্যারেন্ট পর্যন্ত পৌঁছায়। প্যারেন্টের ইভেন্ট লিসেনার তখন event.target
প্রোপার্টি ব্যবহার করে সনাক্ত করতে পারে ঠিক কোন চাইল্ড এলিমেন্টটিতে ইভেন্টটি ursprünglich ঘটেছিল।
সুবিধা:
- কম মেমোরি ব্যবহার: অনেকগুলো ইভেন্ট লিসেনারের পরিবর্তে মাত্র একটি ব্যবহার হয়।
- পারফরম্যান্স: ইভেন্ট লিসেনার সেট আপ করার সময় কমে যায়।
- ডাইনামিক এলিমেন্টের জন্য কার্যকর: যদি জাভাস্ক্রিপ্টের মাধ্যমে প্যারেন্টের ভেতরে নতুন চাইল্ড এলিমেন্ট যোগ করা হয়, তাদের জন্য আলাদা করে ইভেন্ট লিসেনার যোগ করার প্রয়োজন হয় না; প্যারেন্টের ডেলিগেটেড লিসেনারটি তাদের জন্যও কাজ করবে।
const userListUL = document.getElementById("userList"); // ul এলিমেন্ট
userListUL.addEventListener("click", function (event) {
// event.target হলো সেই এলিমেন্ট যেখানে ক্লিক করা হয়েছে (যেমন li বা button)
// event.currentTarget হলো সেই এলিমেন্ট যেখানে লিসেনারটি যুক্ত (ul)
if (event.target && event.target.tagName === "LI") {
console.log(
"একটি লিস্ট আইটেমে ক্লিক করা হয়েছে:",
event.target.textContent
);
}
// যদি লিস্ট আইটেমের ভেতরে কোনো বাটনে ক্লিক হয় (যেমন ডিলিট বাটন)
if (event.target && event.target.classList.contains("delete-button")) {
const listItem = event.target.closest("li"); // বাটনটির সবচেয়ে কাছের li প্যারেন্ট
if (listItem) {
console.log("ডিলিট বাটনে ক্লিক:", listItem.textContent);
// listItem.remove(); // উদাহরণস্বরূপ, আইটেমটি মুছে ফেলা
}
}
});
প্রজেক্ট: দেশের তথ্যভান্ডার (RestCountries API ও LocalStorage ব্যবহার করে) 🌍💾
এখন আমরা একটি বাস্তব প্রজেক্ট করব। https://restcountries.com/
একটি ফ্রি API যা বিভিন্ন দেশের তথ্য প্রদান করে। আমরা এই API থেকে তথ্য এনে DOM ম্যানিপুলেশনের মাধ্যমে ওয়েব পেজে দেখাব এবং ব্যবহারকারী চাইলে কিছু দেশকে "প্রিয়" হিসেবে লোকাল স্টোরেজে সংরক্ষণ করতে পারবে।
উদ্দেশ্য:
- API থেকে সব দেশের নাম, রাজধানী, পতাকা, জনসংখ্যা এবং অঞ্চল এনে সুন্দরভাবে কার্ড আকারে দেখানো।
- প্রতিটি কার্ডে একটি "প্রিয়তে যোগ করুন" বাটন থাকবে।
- প্রিয় দেশগুলো লোকাল স্টোরেজে সেভ হবে এবং পেজ লোড হওয়ার সময় প্রিয় দেশগুলো আলাদাভাবে দেখানো হবে বা হাইলাইট করা হবে।
ধাপসমূহ:
১. HTML কাঠামো তৈরি (index.html
):
একটি কন্টেইনার যেখানে দেশগুলোর কার্ড দেখানো হবে, একটি লোডিং মেসেজ এবং প্রিয় দেশগুলো দেখানোর জন্য একটি আলাদা সেকশন।
<!DOCTYPE html>
<html lang="bn">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>দেশের তথ্যভান্ডার</title>
<style>
body {
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
background-color: #f0f2f5;
color: #333;
}
.container {
max-width: 1200px;
margin: 20px auto;
padding: 20px;
}
header {
text-align: center;
margin-bottom: 30px;
color: #1a237e;
}
header h1 {
margin: 0;
font-size: 2.5em;
}
.section-title {
font-size: 1.8em;
color: #3f51b5;
border-bottom: 2px solid #3f51b5;
padding-bottom: 5px;
margin-top: 30px;
margin-bottom: 20px;
}
#countries-container,
#favorite-countries-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 25px;
}
.country-card {
background-color: white;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
overflow: hidden;
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
}
.country-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
}
.country-card img {
width: 100%;
height: 180px;
object-fit: cover;
border-bottom: 1px solid #eee;
}
.card-content {
padding: 20px;
}
.card-content h3 {
margin-top: 0;
margin-bottom: 10px;
color: #333;
font-size: 1.4em;
}
.card-content p {
margin-bottom: 8px;
font-size: 0.95em;
color: #555;
line-height: 1.6;
}
.card-content p strong {
color: #3f51b5;
}
.fav-button {
background-color: #673ab7;
color: white;
border: none;
padding: 8px 12px;
border-radius: 5px;
cursor: pointer;
font-size: 0.9em;
transition: background-color 0.2s;
display: block;
margin-top: 15px;
width: 100%;
}
.fav-button:hover {
background-color: #512da8;
}
.fav-button.favorited {
background-color: #ff4081;
}
.fav-button.favorited:hover {
background-color: #f50057;
}
#loading,
#error-message {
text-align: center;
font-size: 1.2em;
margin-top: 50px;
padding: 20px;
color: #757575;
}
#error-message {
color: #d32f2f;
background-color: #ffebee;
border: 1px solid #d32f2f;
border-radius: 5px;
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>বিশ্বের দেশসমূহ</h1>
</header>
<div id="favorite-countries-section">
<h2 class="section-title">প্রিয় দেশসমূহ</h2>
<div id="favorite-countries-container">
<p id="no-favorites-message">
এখনো কোনো দেশকে প্রিয় হিসেবে যোগ করা হয়নি।
</p>
</div>
</div>
<h2 class="section-title">সকল দেশ</h2>
<div id="loading">তথ্য লোড হচ্ছে... অনুগ্রহ করে অপেক্ষা করুন।</div>
<div id="error-message" style="display: none;"></div>
<div id="countries-container"></div>
</div>
<script src="app.js"></script>
</body>
</html>
২. জাভাস্ক্রিপ্ট (app.js
): তথ্য আনা, দেখানো এবং সংরক্ষণ করা
document.addEventListener("DOMContentLoaded", () => {
const countriesContainer = document.getElementById("countries-container");
const favoriteCountriesContainer = document.getElementById(
"favorite-countries-container"
);
const noFavoritesMessage = document.getElementById("no-favorites-message");
const loadingMessage = document.getElementById("loading");
const errorMessageDiv = document.getElementById("error-message");
let allCountriesData = []; // সব দেশের ডেটা এখানে রাখা হবে
let favoriteCountries = loadFavorites(); // লোকাল স্টোরেজ থেকে প্রিয় দেশ লোড করা
// API থেকে তথ্য আনার জন্য async ফাংশন
async function fetchCountries() {
try {
loadingMessage.style.display = "block";
errorMessageDiv.style.display = "none";
const response = await fetch("https://restcountries.com/v3.1/all");
if (!response.ok) {
throw new Error(
`HTTP error! status: ${response.status} - ${response.statusText}`
);
}
allCountriesData = await response.json();
loadingMessage.style.display = "none";
displayCountries(allCountriesData, countriesContainer, false); // সকল দেশ দেখানো
displayFavoriteCountries(); // প্রিয় দেশ দেখানো
} catch (error) {
loadingMessage.style.display = "none";
errorMessageDiv.textContent = `দুঃখিত, তথ্য আনতে সমস্যা হয়েছে: ${error.message}`;
errorMessageDiv.style.display = "block";
console.error("Fetch error:", error);
}
}
// দেশগুলোর তথ্য DOM-এ দেখানোর ফাংশন
function displayCountries(countries, container, isFavoriteSection) {
container.innerHTML = ""; // আগের কোনো ডেটা থাকলে মুছে ফেলা
if (countries.length === 0 && isFavoriteSection) {
noFavoritesMessage.style.display = "block";
return;
} else if (isFavoriteSection) {
noFavoritesMessage.style.display = "none";
}
countries.forEach((country) => {
const countryCode = country.cca3; // একটি ইউনিক কোড (যেমন USA, BGD)
const isFavorited = favoriteCountries.includes(countryCode);
const countryCard = document.createElement("div");
countryCard.classList.add("country-card");
countryCard.setAttribute("data-country-code", countryCode);
const countryFlag = document.createElement("img");
countryFlag.src =
country.flags.svg ||
country.flags.png ||
"path/to/local/placeholder.png";
countryFlag.alt = `পতাকা: ${country.name.common || ""}`;
const cardContent = document.createElement("div");
cardContent.classList.add("card-content");
const countryName = document.createElement("h3");
countryName.textContent = country.name.common || "নাম নেই";
const countryCapital = document.createElement("p");
countryCapital.innerHTML = `<strong>রাজধানী:</strong> ${
country.capital ? country.capital.join(", ") : "নেই"
}`;
const countryPopulation = document.createElement("p");
countryPopulation.innerHTML = `<strong>জনসংখ্যা:</strong> ${
country.population
? country.population.toLocaleString("bn-BD")
: "অজানা"
}`;
const countryRegion = document.createElement("p");
countryRegion.innerHTML = `<strong>অঞ্চল:</strong> ${
country.region || "অজানা"
}`;
const favButton = document.createElement("button");
favButton.classList.add("fav-button");
favButton.textContent = isFavorited
? "প্রিয় থেকে সরান"
: "প্রিয়তে যোগ করুন";
if (isFavorited) {
favButton.classList.add("favorited");
}
favButton.addEventListener("click", () =>
toggleFavorite(countryCode, country)
);
cardContent.appendChild(countryName);
cardContent.appendChild(countryCapital);
cardContent.appendChild(countryPopulation);
cardContent.appendChild(countryRegion);
cardContent.appendChild(favButton);
countryCard.appendChild(countryFlag);
countryCard.appendChild(cardContent);
container.appendChild(countryCard);
});
}
// প্রিয় দেশগুলো দেখানোর ফাংশন
function displayFavoriteCountries() {
const favoriteCountryObjects = allCountriesData.filter((country) =>
favoriteCountries.includes(country.cca3)
);
displayCountries(favoriteCountryObjects, favoriteCountriesContainer, true);
}
// লোকাল স্টোরেজ থেকে প্রিয় দেশ লোড করা
function loadFavorites() {
const favorites = localStorage.getItem("favoriteCountries");
return favorites ? JSON.parse(favorites) : [];
}
// লোকাল স্টোরেজে প্রিয় দেশ সেভ করা
function saveFavorites() {
localStorage.setItem(
"favoriteCountries",
JSON.stringify(favoriteCountries)
);
}
// প্রিয় দেশ টগল করার ফাংশন
function toggleFavorite(countryCode, country) {
const index = favoriteCountries.indexOf(countryCode);
if (index > -1) {
favoriteCountries.splice(index, 1); // প্রিয় থেকে সরানো
} else {
favoriteCountries.push(countryCode); // প্রিয়তে যোগ করা
}
saveFavorites();
updateFavoriteButtonStatus(countryCode, index === -1); // বাটন আপডেট
displayFavoriteCountries(); // প্রিয় সেকশন রি-রেন্ডার
}
// নির্দিষ্ট দেশের কার্ডের ফেভারিট বাটন আপডেট করা
function updateFavoriteButtonStatus(countryCode, isNowFavorited) {
const allCards = document.querySelectorAll(
`.country-card[data-country-code="${countryCode}"]`
);
allCards.forEach((card) => {
const button = card.querySelector(".fav-button");
if (button) {
button.textContent = isNowFavorited
? "প্রিয় থেকে সরান"
: "প্রিয়তে যোগ করুন";
if (isNowFavorited) {
button.classList.add("favorited");
} else {
button.classList.remove("favorited");
}
}
});
}
// প্রাথমিক ফাংশন কল
fetchCountries();
});
ব্যাখ্যা (জাভাস্ক্রিপ্ট):
DOMContentLoaded
: নিশ্চিত করে যে পুরো HTML পেজ লোড হওয়ার পরই জাভাস্ক্রিপ্ট কোড চলবে।fetchCountries()
:async/await
ব্যবহার করে RestCountries API থেকে সব দেশের তথ্য আনে। লোডিং মেসেজ এবং ত্রুটি ব্যবস্থাপনা এখানে করা হয়েছে।allCountriesData
অ্যারেতে সব দেশের মূল ডেটা সংরক্ষণ করা হয়, যাতে বারবার API কল করতে না হয়।favoriteCountries
অ্যারেতে প্রিয় দেশগুলোর ইউনিক কোড (cca3
) লোকাল স্টোরেজ থেকে লোড করা হয়।displayCountries()
: এই ফাংশনটি একটি দেশগুলোর অ্যারে এবং একটি কন্টেইনার এলিমেন্ট নেয়, এবং প্রতিটি দেশের জন্য একটি কার্ড তৈরি করে DOM-এ দেখায়।- প্রতিটি কার্ডে দেশের নাম, পতাকা, রাজধানী, জনসংখ্যা, অঞ্চল এবং একটি "প্রিয়" বাটন থাকে।
country.cca3
(যেমন 'USA', 'BGD') প্রতিটি দেশের জন্য একটি ইউনিক আইডেন্টিফায়ার হিসেবে ব্যবহৃত হচ্ছে।
displayFavoriteCountries()
: শুধুমাত্র প্রিয় দেশগুলোর ডেটাallCountriesData
থেকে ফিল্টার করেdisplayCountries
ফাংশনের মাধ্যমে প্রিয় দেশের সেকশনে দেখায়।loadFavorites()
: পেজ লোড হওয়ার সময়localStorage
থেকেfavoriteCountries
নামের আইটেমটি (JSON.parse
করে) রিট্রিভ করে।saveFavorites()
:favoriteCountries
অ্যারেটিকেJSON.stringify()
করেlocalStorage
-এ সেভ করে।toggleFavorite()
: কোনো দেশের "প্রিয়" বাটনে ক্লিক করলে এই ফাংশনটি কল হয়। এটিfavoriteCountries
অ্যারেতে দেশটির কোড যোগ বা বিয়োগ করে,localStorage
আপডেট করে, বাটনের টেক্সট ও স্টাইল পরিবর্তন করে এবং প্রিয় দেশের সেকশন রি-রেন্ডার করে।updateFavoriteButtonStatus()
: যখন একটি দেশ প্রিয় তালিকা থেকে যোগ বা বিয়োগ করা হয়, তখন "সকল দেশ" সেকশনে থাকা সেই দেশের কার্ডের বাটনের স্ট্যাটাসও যেন আপডেট হয়, সেই কাজটি এই ফাংশন করে।
এই প্রজেক্টটি API থেকে ডেটা আনা, DOM ম্যানিপুলেশন এবং লোকাল স্টোরেজে ডেটা সংরক্ষণের একটি ভালো উদাহরণ।
আপনার জন্য চ্যালেঞ্জ: আরও ইন্টারেক্টিভ "দেশের তথ্যভান্ডার" 🚀
উপরের প্রজেক্টটিকে ভিত্তি করে, আপনি নিচের ফিচারগুলো যোগ করার চেষ্টা করতে পারেন। এই চ্যালেঞ্জগুলো সম্পন্ন করার মাধ্যমে আপনি DOM ম্যানিপুলেশন, ইভেন্ট হ্যান্ডলিং, অ্যাসিঙ্ক্রোনাস প্রোগ্রামিং এবং API-এর সাথে কাজ করার দক্ষতা আরও ভালোভাবে রপ্ত করতে পারবেন।
চ্যালেঞ্জের ধাপসমূহ:
-
অনুসন্ধান (Search) সুবিধা:
- ডেভেলপমেন্ট: পেজের উপরের দিকে একটি ইনপুট ফিল্ড (
<input type="text" id="searchInput" placeholder="দেশের নাম লিখুন...">
) যোগ করুন। - ব্যবহারকারী যখন ইনপুট ফিল্ডে কোনো দেশের নাম টাইপ করবে, তখন সেই নামের সাথে (আংশিক বা সম্পূর্ণ) মিলে যাওয়া দেশগুলো যেন "সকল দেশ" সেকশনে ফিল্টার হয়ে শুধুমাত্র সেগুলোই কার্ড আকারে দেখানো হয়।
- ইঙ্গিত:
searchInput
এলিমেন্টেinput
ইভেন্ট লিসেনার যোগ করুন। প্রতিবার ইনপুটের পরিবর্তনে,allCountriesData
অ্যারে থেকেcountry.name.common
-এর উপর ভিত্তি করেArray.prototype.filter()
ব্যবহার করে দেশ ফিল্টার করুন। ব্যবহারকারীর ইনপুট এবং দেশের নাম উভয়কেইtoLowerCase()
করে কেস-ইনসেনসিটিভ সার্চ করুন। ফিল্টার করা অ্যারে দিয়েdisplayCountries()
ফাংশনটি কল করুন (সকল দেশের কন্টেইনারের জন্য)।
- ডেভেলপমেন্ট: পেজের উপরের দিকে একটি ইনপুট ফিল্ড (
-
অঞ্চলভিত্তিক ফিল্টার (Region Filter):
- ডেভেলপমেন্ট: একটি ড্রপডাউন মেনু (
<select id="regionFilter">
) তৈরি করুন। এই ড্রপডাউনে বিভিন্ন অঞ্চলের নাম (<option>
) থাকবে (যেমন: "সকল অঞ্চল", "Asia", "Europe", "Africa", "Americas", "Oceania")। - ব্যবহারকারী কোনো অঞ্চল সিলেক্ট করলে যেন "সকল দেশ" সেকশনে শুধুমাত্র সেই অঞ্চলের দেশগুলো দেখানো হয়। "সকল অঞ্চল" সিলেক্ট করলে সব দেশ দেখানো হবে।
- ইঙ্গিত:
regionFilter
এলিমেন্টেchange
ইভেন্ট লিসেনার যোগ করুন। সিলেক্টেড অঞ্চলের ভ্যালু (event.target.value
) নিন। যদি "সকল অঞ্চল" না হয়, তাহলেallCountriesData
অ্যারে থেকেcountry.region
প্রোপার্টির ওপর ভিত্তি করে ফিল্টার করুন। ফিল্টার করা অ্যারে দিয়েdisplayCountries()
ফাংশনটি কল করুন।
- ডেভেলপমেন্ট: একটি ড্রপডাউন মেনু (
-
বিস্তারিত তথ্য প্রদর্শন (Detailed View on Click):
- ডেভেলপমেন্ট: যখন কোনো দেশের কার্ডে (পতাকা বা নাম অংশে) ক্লিক করা হবে, তখন সেই দেশটির আরও বিস্তারিত তথ্য (যেমন: মুদ্রা (currencies), ভাষা (languages), সীমানা ভাগ করা দেশসমূহ (borders), টাইমজোন (timezones), উপ-অঞ্চল (subregion), মানচিত্রের লিংক (maps.google)) একটি মডাল (Modal) পপ-আপ উইন্ডোতে সুন্দরভাবে দেখানো যেতে পারে।
- ইঙ্গিত:
countriesContainer
এবংfavoriteCountriesContainer
-এ ইভেন্ট ডেলিগেশন ব্যবহার করেclick
ইভেন্ট লিসেন করুন। যদি কোনো কার্ডের নির্দিষ্ট অংশে (যেমন একটি<div>
যা বিস্তারিত তথ্যের জন্য ক্লিকযোগ্য) ক্লিক হয়, তাহলেevent.target.closest('.country-card').getAttribute('data-country-code')
ব্যবহার করে দেশের কোড পান।allCountriesData
থেকে সেই দেশের সম্পূর্ণ অবজেক্টটি খুঁজে বের করুন।- মডাল তৈরির জন্য: একটি
div
(প্রাথমিকভাবেdisplay: none;
করা) এইচটিএমএল-এ তৈরি করুন। যখন বিস্তারিত তথ্য দেখাতে হবে, তখন এইdiv
-এর কনটেন্ট ডাইনামিকভাবে সেট করুন এবংdisplay: block;
বাflex;
করে দৃশ্যমান করুন। মডালে একটি "বন্ধ করুন" বাটনও রাখুন। - সীমানা ভাগ করা দেশগুলোর ক্ষেত্রে, তাদের কোড (
cca3
) দেওয়া থাকে। আপনি চাইলে সেই কোডগুলোকে পুরো নামে রূপান্তর করে দেখাতে পারেন (এর জন্যallCountriesData
আবার ব্যবহার করতে হতে পারে)।
- মডাল তৈরির জন্য: একটি
-
সাজানো (Sorting) অপশন:
- ডেভেলপমেন্ট: ব্যবহারকারীকে দেশগুলো নাম (বর্ণানুক্রমিকভাবে) বা জনসংখ্যা (কম থেকে বেশি বা বেশি থেকে কম) অনুযায়ী সাজানোর অপশন দিন। এটি ড্রপডাউন বা বাটনের মাধ্যমে করা যেতে পারে।
- ইঙ্গিত:
Array.prototype.sort()
মেথড ব্যবহার করুন। নামের জন্যString.prototype.localeCompare()
এবং জনসংখ্যার জন্য সাধারণ বিয়োগ (a.population - b.population
বাb.population - a.population
) ব্যবহার করতে পারেন। সাজানোর পরdisplayCountries()
ফাংশন কল করুন।
-
থিম পরিবর্তন (ডার্ক/লাইট মোড - ঐচ্ছিক):
- ডেভেলপমেন্ট: একটি টগল বাটন যোগ করুন, যা পেজের থিম লাইট এবং ডার্ক মোডের মধ্যে পরিবর্তন করবে।
- ইঙ্গিত: CSS ভ্যারিয়েবল (Custom Properties) ব্যবহার করে কালার স্কিম তৈরি করুন। জাভাস্ক্রিপ্ট দিয়ে
body
বাhtml
এলিমেন্টে একটি ক্লাস (যেমনdark-theme
) টগল করুন এবং সেই ক্লাসের উপর ভিত্তি করে CSS ভ্যারিয়েবলের মান পরিবর্তন করুন। ব্যবহারকারীর পছন্দlocalStorage
-এ সেভ করে রাখতে পারেন।
এই চ্যালেঞ্জগুলো সম্পন্ন করার মাধ্যমে আপনি একজন দক্ষ ফ্রন্ট-এন্ড ডেভেলপার হওয়ার পথে আরও এক ধাপ এগিয়ে যাবেন।
এই DOM সিরিজের মাধ্যমে আমরা ওয়েব পেজের এই "প্রাণকেন্দ্র" এবং জাভাস্ক্রিপ্টের "জাদুকরী স্পর্শ" সম্পর্কে বিস্তারিত জানার চেষ্টা করেছি। প্রথম পর্বের মৌলিক ধারণা থেকে শুরু করে আজকের এই বাস্তব প্রজেক্ট এবং চ্যালেঞ্জ পর্যন্ত, আশা করি প্রতিটি ধাপ আপনাদের ওয়েব ডেভেলপমেন্ট যাত্রায় নতুন দিগন্ত উন্মোচন করেছে। মনে রাখবেন, শেখার সবচেয়ে ভালো উপায় হলো নিজে থেকে চেষ্টা করা এবং প্রজেক্ট তৈরি করা। শুভকামনা!