HTMLCollection VS NodeList
Tags: javascript, htmlcollection, nodelist, dom
Published: 2023-08-13 21:11:31

DOM নিয়ে কাজ করার সময় আমাদের অনেকের একটা প্রশ্ন জাগতে পারেঃ 

DOM মেথডগুলো ব্যবহার করার সময় কেনো কিছু কিছু মেথড এর জন্য কন্সল এ HTMLCollection লিখা থাকে আবার কিছু কিছু মেথড এর জন্য কন্সল এ NodeList লিখা থাকে। কেনো?? HTMLCollection এবং NodeList এর মানে কি? তাদের মধ্যে কি কোনো ভিন্নতা আছে? থাকলে সেগুলো কি কি?? 😵

এই ব্লগটিতে আমি এগুলো নিয়ে in-depth আলোচনা করব।

**HTMLCollection** এবং **NodeList** হচ্ছে একটা **array-like অবজেক্ট**। **মানে array এর মতো দেখতে কিন্তু আসলে একটা অবজেক্ট।**

**<u>HTMLCollection</u>**

**getElementsByClassName()** এবং **getElementsByTagName()** - এই দুইটি মেথড আমাদেরকে একের অধিক element রিটার্ন করে। আমরা যখন এই মেথডগুলো ব্যবহার করি JavaScript আমাদেরকে element গুলো একটা HTMLCollection এ রেখে রিটার্ন করে। 

যেমন ধরো, একটা ওয়েবপেইজ এ list of books দেওয়া আছে এবং আমাদেরকে প্রত্যেকটা list item access করতে হবে।যদি আমরা **getElementsByTagName()** দিয়ে access করি তাহলে output এ কি দেখবো?🤔

**_index.html_**
```
   <ul>
      <li>Bangla</li>
      <li>English</li>
      <li>Biology</li>
      <li>Physics</li>
    </ul>
```

**_list.js_**

```
const list = document.getElementsByTagName("li");
console.log(list);

Output
//HTMLCollection(4) [li, li, li, li]
```

আমরা এই example টা থেকে বুঝতে পারলাম HTMLCollection এ শুধু **HTML elements** গুলো store করা হয়। যখন আমরা উপরের কোড এ **getElementsByTagName()** ব্যবহার করেছি আমরা HTMLCollection এ শুধু **li ট্যাগ** গুলো পেলাম। কন্টেন্ট(text) টা দেখতে পারছি না। এর কারণ হচ্ছে, HTMLCollection এ stored থাকে DOM element গুলোর **references**. Actual elements গুলো stored থাকেনা। **_reference মানে কোথাই একটি element DOM এ located আছে সেটা বলে দেওয়া।_**

**<u>NodeList</u>**

DOM হচ্ছে একটা upside down tree-like structure. Node দিয়ে DOM tree বানানো হয়। 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jlv11ey8u43ziyg7pmzy.png)



কিছু **common DOM nodes** হচ্ছেঃ

**1) Element Nodes
2) Text Nodes
3) Attribute Nodes
4) Comment Nodes**

HTMLCollection এর মতো **NodeList** ও একটা **array-like অবজেক্ট**। তবে, আমরা NodeList এ **different types of nodes** রাখতে পারি। 

চলো একটা উদাহরণ দেখিঃ

**_index.html_**
```
<div id="box">
  I'm Text Node
  <div>I'm Element Node 1</div>
  <div>I'm Element Node 2</div>
</div>

```

**_text.js_**
```
const box = document.getElementById("box");
console.log(box.childNodes);

Output 
// NodeList(5) [text, div, text, div, text]
```
আমরা childNodes টা ignore করে একটু output এর উপর ফোকাস করি।   childNodes নিয়ে আমি last এ আলোচনা করব। Output এ আমরা দেখতে পারছি, NodeList tag গুলোর পাশাপাশি টেক্সট গুলোকেও store করেছে। 

NodeList এ main information(element node) এর পাশাপাশি extra information(text node) ও রাখা হয়। এটার benefit টা হচ্ছে আমরা easily different types of node নিয়ে কাজ করতে পারব যেটা অনেক situation আমাদের করা লাগতে পারে। নিচের উদাহরণ দেখলে বুঝতে পারবে।

যেমন ধরো, একটা div এ দুইটা p tag আছে এবং tag ছাড়া একটা text আছে। এখন আমি p tag এর ভিতর text গুলোকে এবং tag ছাড়া text টাকে color দিতে চাই। এখন আমি ট্যাগ ছাড়া টেক্সট টাকে কিভাবে access করব?? 

HTMLCollection দিয়ে করব? HTMLCollection দিয়ে করলে আমি easily p tag গুলো পাবো কিন্তু tag ছাড়া text টা কে কিভাবে পাবো?? NodeList দিয়ে তো করতে পারি তাই না? ইয়েস, NodeList দিয়ে আমরা easily সবগুলোকে color দিতে পারব কারণ NodeList all types of nodes store করে।

**_index.html_**
```
   <div id="container">
      <p>First paragraph</p>
      Some text between paragraphs.
      <p>Second paragraph</p>
    </div>
```

**_text.js_**
```
 // Get the container element
    var container = document.getElementById("container");

 // Get a NodeList containing all child nodes of the container
      var nodes = container.childNodes;

      // Loop through the NodeList
      nodes.forEach(function (node) {
        // Check if the node is a text node
        if (node.nodeType === Node.TEXT_NODE) {
          // Change the text color of text nodes
          node.parentNode.style.color = "red";
        }
      });
```

আমরা কিন্তু HTMLCollection দিয়ে এ কাজটা করতে পারব কিন্তু complex একটা কোড লিখতে হবে তাই NodeList ব্যবহার করলে better.


**querySelectorAll()** এবং **getElementsByName()** ব্যবহার করে আমরা NodeList রিটার্ন করতে পারি।  

```
 const list = document.querySelectorAll("li");
 console.log(list);

output
//NodeList(4) [li, li, li, li]
```

এখন এই পার্ট টা একটু confusing লাগতে পারে। আমি **getElementsByTagName()** দিলে HTMLCollection এ শুধু tag গুলো পাচ্ছি আবার **querySelectorAll()** ব্যবহার করলেও NodeList এ শুধু tag গুলো পাচ্ছি। তাহলে এখানে difference টা কি?? 

Difference টা আলোচনা করার আগে HTMLCollection এবং NodeList এর similarity টা জেনে নেই। 

১) HTMLCollection এবং NodeList এ আমরা loop চালাতে পারব
২) HTMLCollection এবং NodeList এ push এবং pop করতে পারবনা

এখন difference টা জেনে নেই:

- যদিও **querySelectorAll()** আমাদেরকে শুধু tag গুলো NodeList এ দেই আমরা কিন্তু NodeList ব্যবহার করলে কিছু helpful মেথড পাবো যেগুলো মাঝে মাঝে আমাদের কোনো একটা complex কোড এ লাগতে পারে। যেমন ধরো,

  ১) foreach
  ২) entries
  ৩) keys
  ৪) values

আমরা কিন্তু এই মেথডগুলো HTMLCollection এ পাবো না। 

- এরেকটা তফাত হচ্ছে **getElementsByClassName()** এবং **getElementsByTagName()** কে **live** বলে কারণ DOM এ কিছু আপডেট হলে আমরা HTMLCollection এ latest update টা পাবো কিন্তু **querySelectorAll()** এবং **getElementsByName()** ব্যবহার করলে আমরা NodeList এ latest update পাবনা কারণ **querySelectorAll()** এবং **getElementsByName()** হচ্ছে **static**।

<u>HTMLCollection</u>

```
const boxWrapper = document.getElementById("box-wrapper");
const boxes = boxWrapper.getElementsByClassName("box");
console.log(boxes.length); // 4

const div = document.createElement("div");
div.classList.add("box");
div.innerHTML = "box 5";
boxWrapper.appendChild(div);
console.log(boxes.length); // 5

```
<u>NodeList</u>

```
const boxes = document.querySelectorAll(".box");
console.log(boxes.length); // 4

const div = document.createElement("div");
div.setAttribute("class", "box");
div.innerHTML = "box 5";
boxWrapper.appendChild(div);

console.log(boxes.length); // 4
```

- Lastly, children হচ্ছে HTMLCollection এর একটা property যার দ্বারা শুধু  HTML elements গুলো access করতে পারি আর childNodes হচ্ছে NodeList এর property। childNodes দিয়ে all types of nodes access করতে পারি।

**_index.html_**
```
<div id="container">
    <p>First paragraph</p>
    Some text between paragraphs.
    <p>Second paragraph</p>
</div>

```

**_text.js_**

```
var container = document.getElementById('container');

var children = container.children; 
// Only includes <p> elements

var childNodes = container.childNodes; 
// Includes <p>, text, and text nodes

```

HTMLCollection এর ও কিছু benefits আছে আবার NodeList এর ও কিছু benefits আছে তাই কখন HTMLCollection ব্যবহার করব এবং কখন NodeList ব্যবহার সেটা depend করে কোড এর উপর।  

এই ব্লগ থেকে শুধু নিচের key points গুলো বুঝলে হবে:

১) HTMLCollection এ শুধু **HTML elements** store করা যাই আর NodeList এ **all types of nodes** store করা যাই।

২) **getElementsByClassName()** এবং **getElementsByTagName()** কে **live** বলা হয় এবং **querySelectorAll()** এবং **getElementsByName()** কে **static** বলা হয়