DOM মোডিফিকেশনের মাধ্যমে আমরা আমাদের পেইজ কে আরো "ডায়নামিক প্রাণবন্ত" করতে পারি।
এখানে আমরা দেখব কিভাবে বিদ্যমান পেজের কন্টেন্ট সমূহকে "স্বতঃস্ফুর্তভাবে" পরিবর্তন করতে পারি।
চলুন একটি উদাহরণের সাহায্যে এটি বুঝি। আমরা একটি মেসেজ এলিমেন্ট লিখব যা alert
এর মত দেখায়।
এটি দেখতে এমন হবে:
<style>
.alert {
padding: 15px;
border: 1px solid #d6e9c6;
border-radius: 4px;
color: #3c763d;
background-color: #dff0d8;
}
</style>
*!*
<div class="alert">
<strong>Hi there!</strong> You've read an important message.
</div>
*/!*
এটি একটি HTML উদাহরণ। চলুন পুরো ব্যাপারটি আমরা প্রোগ্রামাটিক্যালি জাভাস্ক্রিপ্ট এর সাহায্যে করি (ধরে নিই আমাদের ইতোমধ্যে CSS স্ট্যাইল করা আছে)।
DOM নোড তৈরির জন্য দুটি মেথড আছে:
document.createElement(tag)
: ট্যাগ অনুযায়ী একটি নতুন এলিমেন্ট নোড তৈরি করা:
```js
let div = document.createElement('div');
```
document.createTextNode(text)
: টেক্সট অনুযায়ী একটি নতুন টেক্সট নোড তৈরি করা:
```js
let textNode = document.createTextNode('Here I am');
```
বেশিরভাব ক্ষেত্রে আমাদের এলিমেন্ট নোড তৈরি করা লাগে, যেমন মেসেজ দেখাতে div
এলিমেন্ট।
DIV মেসেজটি তৈরিতে আমাদের তিনটি ধাপের প্রয়োজন:
// 1. <div> এলিমেন্ট তৈরি
let div = document.createElement('div');
// 2. "alert" ক্লাশ নামটি সংযোগ
div.className = "alert";
// 3. কন্টেন্ট সংযোগ
div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";
আমরা এলিমেন্ট তৈরি করেছি। কিন্তু এখনো শুধুমাত্র div
নামের একটি ভ্যারিয়েবল, এটি পেজে সংযুক্ত হবে না। তাই একে দেখতেও পারব না।
div
টি দেখাতে, আমাদের এটি document
এর কোন একটি জায়গায় এটি সংযুক্ত করতে হবে। যেমন, <body>
এলিমেন্ট, যা document.body
দ্বারা সূচিত করা হয়।
এটির একটি স্পেশাল মেথড আছে append
: document.body.append(div)
.
এখানে সম্পুর্ন কোডটি দেখুন:
<style>
.alert {
padding: 15px;
border: 1px solid #d6e9c6;
border-radius: 4px;
color: #3c763d;
background-color: #dff0d8;
}
</style>
<script>
let div = document.createElement('div');
div.className = "alert";
div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";
*!*
document.body.append(div);
*/!*
</script>
এখানে আমরা document.body
তে append
কল করেছি, কিন্তু আমরা চাইলে অন্য এলিমেন্টে সংযুক্ত করতে ঐ এলিমেন্ট সমূহেও append
কল করতে পারি। যেমন, আমরা <div>
এ অন্য এলিমেন্ট সংযুক্ত করতে পারি div.append(anotherElement)
।
এখানে আমরা আরো কিছু ইনসার্ট মেথড দেখব:
node.append(...nodes or strings)
-- নোডের শেষে কোন নোড অথবা স্ট্রিং সংযুক্ত,node.prepend(...nodes or strings)
-- নোডের শুরুতে কোন নোড অথবা স্ট্রিং সংযুক্ত,node.before(...nodes or strings)
–- নোডের পূর্বে কোন নোড অথবা স্ট্রিং সংযুক্ত,node.after(...nodes or strings)
–- নোডের পরে কোন নোড অথবা স্ট্রিং সংযুক্ত,node.replaceWith(...nodes or strings)
–-node
কে অন্য নোড বা স্ট্রিং দ্বারা রিপ্লেস।
মেথডসমূহের আর্গুমেণ্টটি যেকোন স্বতন্ত্র DOM নোড অথবা টেক্সট স্ট্রিং(যা স্বয়ংক্রিয়ভাবে টেক্সট নোড হবে) হতে পারে।
চলুন উদাহরণের সাহায্যে দেখি।
এখানে একটি লিস্ট আছে, এখানে আমরা ইনসার্শন মেথড সমূহ সংযুক্ত করব:
<ol id="ol">
<li>0</li>
<li>1</li>
<li>2</li>
</ol>
<script>
ol.before('before'); // <ol> নোডের পূর্বে "before" স্ট্রিং
ol.after('after'); // <ol> নোডের পর "after" স্ট্রিং
let liFirst = document.createElement('li');
liFirst.innerHTML = 'prepend';
ol.prepend(liFirst); // <ol> এর শুরুতে একটি লিস্ট
let liLast = document.createElement('li');
liLast.innerHTML = 'append';
ol.append(liLast); // <ol> এর শেষে একটি লিস্ট
</script>
মেথডগুলো কিভাবে কাজ করে তার একটি চিত্র এখানে দেখুন:
সুতরাং সর্বশেষে আমাদের DOM টি হবে এমন:
before
<ol id="ol">
<li>prepend</li>
<li>0</li>
<li>1</li>
<li>2</li>
<li>append</li>
</ol>
after
ইতোমধ্যে আমরা জেনেছি আমরা একাধিক নোড বা স্ট্রিং একবার কলের মাধ্যমে সংযুক্ত করতে পারি।
যেমন, এখানে আমরা একটি স্ট্রিং এবং একটি এলিমেন্ট সংযুক্ত করছি:
<div id="div"></div>
<script>
div.before('<p>Hello</p>', document.createElement('hr'));
</script>
দয়া করে নোট করুন: এখানে টেক্সটি একটি স্ট্রিং হিসেবেই সংযুক্ত হবে, "HTML" হিসেবে নয়, প্রপারলি ক্যারাক্টার <
, >
সমূহ এস্কেপ হবে।
সুতরাং সর্বশেষ আউটপুটটি হবে এমন:
*!*
<p>Hello</p>
*/!*
<hr>
<div id="div"></div>
অন্য ভাবে বলা যায়, স্ট্রিং সমূহ নিরাপদ ভাবে সংযুক্ত হয়, elem.textContent
এর মত।
সুতরাং, মেথডসমূহ DOM নোড অথবা টেক্সট হিসেবে সংযুক্ত হয়।
কিন্তু যদি আমরা কোন স্ট্রিংকে "HTML" কন্টেন্ট হিসেবে সংযুক্ত করতে চায়, যা সকল ট্যাগ এবং অন্যান্য ব্যাপার গুলো সহ কাজ করবে অনেকটা elem.innerHTML
এর মত, এভাবে করা কি সম্ভব?
এজন্য আমরা আরেকটি বহুরূপী মেথড ব্যবহার করতে পারি: elem.insertAdjacentHTML(where, html)
।
যার প্রথম প্যারামিটারটি হবে পজিশন, অর্থাৎ elem
এর কোন অবস্থানে সংযুক্ত হবে। নিচে এদের সম্পর্কে আলোচনা করা হল:
"beforebegin"
--elem
শুরুর পূর্বেhtml
টি সংযুক্ত হবে,"afterbegin"
--elem
এর শুরুতেhtml
টি সংযুক্ত হবে,"beforeend"
--elem
টি শেষ হওয়ার পূর্বেhtml
টি সংযুক্ত হবে,"afterend"
--elem
টি শেষ হওয়ার পরhtml
টি সংযুক্ত হবে।
দ্বিতীয় প্যারামিটারটি হবে একটি HTML ট্রিং, যা "HTML" হিসেবে সংযুক্ত হবে।
উদাহরণস্বরূপ:
<div id="div"></div>
<script>
div.insertAdjacentHTML('beforebegin', '<p>Hello</p>');
div.insertAdjacentHTML('afterend', '<p>Bye</p>');
</script>
...যা দেখতে এমন হবে:
<p>Hello</p>
<div id="div"></div>
<p>Bye</p>
এভাবেই আমরা স্বতন্ত্র HTML পেজে সংযুক্ত করতে পারি।
এখানে সংযুক্তকরণের চিত্রটি দেখুন:
এখানে আমরা পূর্বের এবং বর্তমান ছবিটি লক্ষ্য করলে বুঝতে পারি, দুইটি ছবিই একই পজিশন নির্দেশ করে, তবে পার্থক্য হল এই মেথডটির সাহায্যে আমরা স্ট্রিংকে HTML কন্টেন্ট হিসেবে সংযুক্ত করতে পারি।
অনুরূপ আরো দুটি মেথড আছে:
elem.insertAdjacentText(where, text)
-- পূর্বের মত, তবে এটি স্ট্রিং হিসেবেtext
নিবে এবং "টেক্সট" হিসেবে সংযুক্ত হবে,elem.insertAdjacentElement(where, elem)
-- একই কাজ করবে, তবে শুধুমাত্র এলিমেন্ট সংযুক্ত হবে।
তবে বেশিরভাগ ক্ষেত্রে এদের আলাদা করে ব্যবহার করা হয়না। বাস্তবিক ক্ষেত্রে আমরা বেশিরভাগ সময় শুধুমাত্র insertAdjacentHTML
ব্যবহার করব। কেননা এলিমেন্ট এবং টেক্সটের জন্য আমাদের append/prepend/before/after
মেথড সমূহ আছে -- টেক্সট ইনসার্শনের জন্য এরা বেশি সুবিধাজনক।
আমরা এভাবেও মেসেজটি দেখাতে পারি:
<style>
.alert {
padding: 15px;
border: 1px solid #d6e9c6;
border-radius: 4px;
color: #3c763d;
background-color: #dff0d8;
}
</style>
<script>
document.body.insertAdjacentHTML("afterbegin", `<div class="alert">
<strong>Hi there!</strong> You've read an important message.
</div>`);
</script>
কোন নোড রিমুভ করতে একটি মেথড আছে - node.remove()
।
চলুন আমাদের মেসেজটিকে এক সেকেন্ড পর DOM হতে রিমুভ করি:
<style>
.alert {
padding: 15px;
border: 1px solid #d6e9c6;
border-radius: 4px;
color: #3c763d;
background-color: #dff0d8;
}
</style>
<script>
let div = document.createElement('div');
div.className = "alert";
div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";
document.body.append(div);
*!*
setTimeout(() => div.remove(), 1000);
*/!*
</script>
দয়া করে নোট করুন: যদি আমরা এলিমেন্টটিকে অন্য আরেক এলিমেন্টের মধ্যে move করাতে চাই -- তাহলে আমাদের পূর্বের নোডটি remove করতে হবে না।
সকল ইনসার্শন মেথড স্বয়ংক্রিয়ভাবে পুরনো নোডটি DOM হতে রিমুভ করে দেয়।
উদাহরণস্বরূপ, এলিমেন্টকে অদল বদল করি:
<div id="first">First</div>
<div id="second">Second</div>
<script>
// remove কল করা লাগবে না
second.after(first); // #second টির মধ্যে #first টি সংযুক্ত হবে
</script>
কিভাবে আমরা অনূরূপ আরেকটি মেসেজ সংযুক্ত করত্র পারি?
আমরা একটি ফাংশন তৈরির মাধ্যমে এটি করতে পারি। কিন্তু আমাদের বিকল্প আরেকটি উপায় আছে clone যা বর্তমান div
কে ক্লোন করবে এবং আমরা চাইলে একে পরিবর্তন করতে পারি (যদি আমাদের প্রয়োজন হয়)।
অনেক সময় আমাদের অনেক বড় এলিমেন্ট থাকতে পারে, এক্ষেত্রে এটি সহজে এবং দ্রুত কাজ করবে।
elem.cloneNode(true)
কলে এলিমেন্টটির একটি "ডীপ" ক্লোন তৈরি করে -- সকল সাব এলিমেন্ট এবং অ্যাট্রিবিউট সহ। যদি আমরাelem.cloneNode(false)
এভাবে ক্রিয়েট করি, তাহলে সাব এলিমেন্ট ব্যতীত ক্লোন হবে।
মেসেজ কপি করার একটি উদাহরণ:
<style>
.alert {
padding: 15px;
border: 1px solid #d6e9c6;
border-radius: 4px;
color: #3c763d;
background-color: #dff0d8;
}
</style>
<div class="alert" id="div">
<strong>Hi there!</strong> You've read an important message.
</div>
<script>
*!*
let div2 = div.cloneNode(true); // মেসেজ ক্লোন
div2.querySelector('strong').innerHTML = 'Bye there!'; // ক্লোন করা এলিমেন্টের strong এলিমেন্টকে পরিবর্তন
div.after(div2); // div এর পরে ক্লোন করা এলিমেন্টটি দেখানো হল
*/!*
</script>
DocumentFragment
হল একটি বিশেষ DOM নোড যা একটি র্যাপার হিসেবে কাজ করে, এবং একে আমরা অন্য নোডে সংযুক্ত করতে পারি।
আমরা অন্যান্য নোড এর মধ্যে সংযুক্তকরণের সময়, এটি সংযুক্ত হওয়ার পরিবর্তে এর কন্টেন্ট সমূহ সংযুক্ত হয়।
যেমন, getListContent
ফাংশনটি <li>
আইটেমের একটি ফ্রাগমেন্ট তৈরি করে, এবং এর পর <ul>
এর মধ্যে সংযুক্ত করলাম:
<ul id="ul"></ul>
<script>
function getListContent() {
let fragment = new DocumentFragment();
for(let i=1; i<=3; i++) {
let li = document.createElement('li');
li.append(i);
fragment.append(li);
}
return fragment;
}
*!*
ul.append(getListContent()); // (*)
*/!*
</script>
দয়া করে নোট করুন, শেষ লাইনে (*)
আমরা DocumentFragment
সংযুক্ত করলাম, কিন্তু এটি "মিশ্রিত" অবস্থায় আছে, সুতরাং আউটপুটটি হবে:
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
DocumentFragment
কদাচিৎ ব্যবহার হয়। কেন আমাদের এই ধরণের বিশেষ নোডের দরকার হয়, যখন আমরা এটি এভাবে করতে পারি? নিচের উদাহরণটি দেখুন:
<ul id="ul"></ul>
<script>
function getListContent() {
let result = [];
for(let i=1; i<=3; i++) {
let li = document.createElement('li');
li.append(i);
result.push(li);
}
return result;
}
*!*
ul.append(...getListContent()); // append + "..." operator = friends!
*/!*
</script>
পূর্বেই উল্লেখ করেছি DocumentFragment
আমাদের বিশেষ কিছু কন্সেপ্টের জন্য দরকার হয়, যেমন template এলিমেন্ট, যা পরবর্তীতে আমরা আলোচনা করব।
[old]
এছাড়াও কিছু "পুরনো" DOM ম্যানিপুলেশন মেথড আছে, যা এখনো বিদ্যমান।
মেথডগুলো পুরনো জাভাস্ক্রিপ্টে ব্যবহার হত। বর্তমানে, মডার্ন জাভাস্ক্রিপ্টে আমাদের ঐ মেথড সমূহ ব্যবহারের দরকার পড়ে না, যেমন append
, prepend
, before
, after
, remove
, replaceWith
এই মেথড সমূহ অনেক বেশি কার্যকরী।
এখানে এদের নিয়ে আলোচনার একটি কারণ হল, পুরনো অনেক স্ক্রিপ্টে আমরা এদের ব্যবহার দেখতে পায়:
parentElem.appendChild(node)
: parentElem
এর সবার শেষে node
সংযুক্তকরণে।
নিচের উদাহরণে `<ol>` এর একদম শেষে নতুন একটি `<li>` আইটেম সংযুক্তকরণ করা হল:
```html run height=100
<ol id="list">
<li>0</li>
<li>1</li>
<li>2</li>
</ol>
<script>
let newLi = document.createElement('li');
newLi.innerHTML = 'Hello, world!';
list.appendChild(newLi);
</script>
```
parentElem.insertBefore(node, nextSibling)
: parentElem
এর নির্দিষ্ট অবস্থানে node
সংযুক্তকরণ।
নিচের উদাহরণে দ্বিতীয় অবস্থানে `<li>` আইটেমটি সংযুক্ত হবে:
```html run height=100
<ol id="list">
<li>0</li>
<li>1</li>
<li>2</li>
</ol>
<script>
let newLi = document.createElement('li');
newLi.innerHTML = 'Hello, world!';
*!*
list.insertBefore(newLi, list.children[1]);
*/!*
</script>
```
`newLi` কে প্রথম এলিমেন্ট হিসেবে সংযুক্ত করতে পারি এভাবে:
```js
list.insertBefore(newLi, list.firstChild);
```
parentElem.replaceChild(node, oldChild)
: parentElem
এ oldChild
কে node
দ্বারা পরিবর্তন।
parentElem.removeChild(node)
: parentElem
হতে node
কে বাদ দিতে (ধরে নিন node
হল parentElem
এর একটি চাইল্ড)।
নিচের উদাহরণে `<ol>` হতে প্রথম `<li>` কে বাদ দেয়া দেখানো হল:
```html run height=100
<ol id="list">
<li>0</li>
<li>1</li>
<li>2</li>
</ol>
<script>
let li = list.firstElementChild;
list.removeChild(li);
</script>
```
সকল মেথড inserted/removed নোডটিকে রিটার্ন করবে। অন্যভাবে বলা যায়, parentElem.appendChild(node)
মেথডটি node
টিকে রিটার্ন করে। তবে সাধারণত আমরা রিটার্ন ভ্যালু ব্যবহার করিনা, বেশিরভাগ ক্ষেত্রে শুধুমাত্র মেথডটি রান হয়।
এছাড়াও আরো একটি পুরনো উপায় আছে, যার মাধ্যমে আমরা পেজে কিছু দেখায়: document.write
।
সিন্ট্যাক্সটি হল:
<p>Somewhere in the page...</p>
*!*
<script>
document.write('<b>Hello from JS</b>');
</script>
*/!*
<p>The end</p>
document.write(html)
কলের মাধ্যমে আমরা html
এ "নির্দিষ্ট অবস্থানে" লিখতে পারি। html
স্ট্রিং ডায়নামিক্যালি জেনারেট হয়, সুতরাং এটি আরো বেশি কার্যকরী। আমরা জাভাস্ক্রিপ্টের সাহায্যে একটি সম্পূর্ন ওয়েবপেজ লিখতে পারি।
মেথডটি অনেক পুরনো যখন কোন স্পেসিফিক DOM ছিল না, বা কোন স্ট্যান্ডার্ড ছিল না। এবং এটি এখনো ব্যবহার হয়, কেননা স্ক্রিপ্টে এটি ব্যবহৃত।
মডার্ন স্ক্রিপ্টে এটি তেমন ব্যবহার করা হয় না, কেননা এর কিছু লিমিটেশন আছে:
document.write
কাজ করে শুধুমাত্র পেজ লোডিংয়ের সময়।
যদি আমরা পরে এটি কল করি, বর্তমান ডকুমেন্ট কন্টেন্টটি মুছে যাবে।
উদাহরণস্বরূপ:
<p>After one second the contents of this page will be replaced...</p>
*!*
<script>
// ১ সেকেন্ড পর document.write
// পেজ লোড হওয়ার পর, এক্সিক্টেন্ট কন্টেন্ট মুছে যাবে
setTimeout(() => document.write('<b>...By this.</b>'), 1000);
</script>
*/!*
সুতরাং এটি পেজ "লোড সম্পন্ন" হওয়ার পর আর ব্যবহার উপযোগী নয়, এটি উপরে আলোচিত অন্যান্য DOM মেথডের মত না।
এটিই এর খারাপ দিক।
তবে এর ভালো দিকও আছে। ট্যাকনিক্যালি, document.write
কল হয় যখন ব্রাউজার ইনকামিং HTML কে পার্স করে, এবং আমরা ডায়নামিক্যালি কিছু লিখতে পারি, ব্রাউজার এটি অন্যান্য HTML টেক্সটের মত মনে করে।
সুতরাং এটি অন্যান্য স্ক্রিপ্ট থেকে অনেক দ্রুত কাজ করে, কেননা এক্ষেত্রে কোন DOM modification হয়না। এটি সরাসরি পেইজে টেক্সট হিসেবে লিখে, এবং ঐ মূহুর্তেও DOM টিও সম্পুর্ণ বিল্ট হয়না।
সুতরাং যদি আমাদের লোডিং টাইমে কোন কন্টেন্ট ডায়নামিক্যালি লিখার দরকার হয়, যেখানে আমাদের দ্রুত করা লাগে, তখন এটি কাজে আসতে পারে। তবে এই ধরণের পরিস্থিতি তেমন আসে না। তারপরও আমাদের এই মেথডসমূহ সম্পর্কে জেনে রাখা উচিত।
-
নতুন নোড তৈরির মেথড:
document.createElement(tag)
-- প্রদত্ত ট্যাগ অনুযায়ী একটি নতুন এলিমেন্ট নোড তৈরি করে,document.createTextNode(value)
-- একটি নতুন টেক্সট নোড তৈরি করে(কদাচিৎ ব্যবহার হয়),elem.cloneNode(deep)
-- এলিমেন্টের ক্লোন করে, যদিdeep==true
হয় তাহলে সকল সাব এলিমেন্ট সহ ক্লোন হয়।
-
ইনসার্শন এবং রিমুভাল:
node.append(...nodes or strings)
-- নোডের শেষে কোন নোড অথবা স্ট্রিং সংযুক্ত,node.prepend(...nodes or strings)
-- নোডের শুরুতে কোন নোড অথবা স্ট্রিং সংযুক্ত,node.before(...nodes or strings)
–- নোডের পূর্বে কোন নোড অথবা স্ট্রিং সংযুক্ত,node.after(...nodes or strings)
–- নোডের পরে কোন নোড অথবা স্ট্রিং সংযুক্ত,node.replaceWith(...nodes or strings)
–-node
কে অন্য নোড বা স্ট্রিং দ্বারা রিপ্লেস।node.remove()
–-node
রিমুভ।
স্ট্রিং সমূহ "text" হিসেবেই সংযুক্ত হয়।
-
এছাড়াও কিছু "পুরনো" মেথড আছে:
parent.appendChild(node)
parent.insertBefore(node, nextSibling)
parent.removeChild(node)
parent.replaceChild(newElem, node)
সকল মেথড
node
টিকে ভ্যালু হিসেবে রিটার্ন করে। -
এছাড়াও
html
আকারে কোন কিছু সংযুক্ত করতে আছে,elem.insertAdjacentHTML(where, html)
এবংwhere
নির্দেশ করে এটি এলিমেন্টের কোন পজিশনে ইনসার্ট হবে:"beforebegin"
--elem
শুরুর পূর্বেhtml
টি সংযুক্ত হবে,"afterbegin"
--elem
এর শুরুতেhtml
টি সংযুক্ত হবে,"beforeend"
--elem
টি শেষ হওয়ার পূর্বেhtml
টি সংযুক্ত হবে,"afterend"
--elem
টি শেষ হওয়ার পরhtml
টি সংযুক্ত হবে।
এছাড়াও অনুরূপ আরো দুটি মেথড আছে,
elem.insertAdjacentText
এবংelem.insertAdjacentElement
, যা যথাক্রমে টেক্সট এবং এলিমেন্টকে স্ট্রিং হিসেবে নেয়, তবে এদের ব্যবহার কদাচিৎ। -
পেজ লোডিং টাইমে কিছু সংযুক্ত করতে:
document.write(html)
পেজ লোড হওয়ার পর পুনরায় এটি কল করলে ডকুমেন্টটি মুছে যায়। পুরনো স্ক্রিপ্টে আমরা এদের দেখি।