জাভাস্ক্রিপ্টে DOM এলিমেন্ট এডিট করার ফাংশন ডুপ্লিকেট করার ভুল
ধরুন আমাদের একটি তালিকা আছে:
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
তালিকা এবং এর আইটেমগুলো আলাদা ভেরিয়েবলে পাই:
let ul = document.querySelector('ul');
let lis = document.querySelectorAll('li');
আসুন এমন করি যাতে আমাদের তালিকার আইটেমগুলো একটি প্রদর্শিত ইনপুট দিয়ে এডিট করা যায়:
for (let li of lis) {
li.addEventListener('click', function func() {
let input = document.createElement('input');
input.value = li.textContent;
li.textContent = '';
li.append(input);
input.addEventListener('blur', function() {
li.textContent = this.value;
li.addEventListener('click', func);
});
li.removeEventListener('click', func);
});
}
ধরুন এখন আমরা চাই যে তালিকায় নতুন আইটেম যোগ করা যায়। এর জন্য তালিকার নিচে একটি সংশ্লিষ্ট ইনপুট থাকুক:
<input id="adder">
এই ইনপুটটির রেফারেন্স একটি ভেরিয়েবলে পাই:
let adder = document.querySelector('#adder');
আসুন এমন করি যাতে ইনপুটের ফোকাস হারানোর সময় আমাদের ইনপুট থেকে নেওয়া টেক্সট সহ একটি নতুন আইটেম তালিকায় যোগ হয়:
adder.addEventListener('blur', function() {
let li = document.createElement('li');
li.textContent = this.value;
ul.append(li);
});
ধরুন এখন আমরা চাই যে নতুন যোগ করা আইটেমগুলিও এডিট করা যায়। তারা নিজে থেকেই এডিট করা যাবে না, কারণ যখন আমরা তালিকার আইটেমগুলিতে ক্লিক হ্যান্ডলার সংযুক্ত করেছিলাম, তখন এই আইটেমগুলি ছিল না।
আসুন এই সমস্যার সম্ভাব্য সমাধানগুলি দেখি।
প্রথম সমাধান
সরলতম সমাধান হল func ফাংশনের কোড
ডুপ্লিকেট করা, নতুন তৈরি করা আইটেমগুলির
জন্যও এটি বাঁধা:
adder.addEventListener('blur', function() {
let li = document.createElement('li');
li.textContent = this.value;
li.addEventListener('click', function func() {
// এখানে আমরা কোড ডুপ্লিকেট করি
});
ul.append(li);
});
অবশ্যই, এই সমাধানে আমরা অবিলম্বে একটি ত্রুটি দেখতে পাই - কোড ডুপ্লিকেট করা সঠিক নয়।
দ্বিতীয় সমাধান
ডুপ্লিকেশন সমস্যা সমাধানের জন্য
func ফাংশনটিকে বাইরে নিয়ে যাওয়া
যৌক্তিক, এটিকে ফাংশন ডিক্লারেশন বানানো:
function func() {
let input = document.createElement('input');
input.value = li.textContent;
li.textContent = '';
li.append(input);
input.addEventListener('blur', function() {
li.textContent = this.value;
li.addEventListener('click', func);
});
li.removeEventListener('click', func);
}
এখানেই আমাদের সমস্যা লুকিয়ে আছে।
ব্যাপারটি হল যে আমাদের ফাংশনটি
বাহ্যিক স্কোপ থেকে প্রাপ্ত li
ভেরিয়েবলটি ব্যবহার করত।
কিন্তু ফাংশনটি বের করার পরে এই
ভেরিয়েবলটি এখন দৃশ্যমান নয়!
সমস্যার সমাধানের জন্য আমাদের
li কে একটি প্যারামিটার হিসেবে
পাঠানো হবে:
function func(li) {
let input = document.createElement('input');
input.value = li.textContent;
li.textContent = '';
li.append(input);
input.addEventListener('blur', function() {
li.textContent = this.value;
li.addEventListener('click', func);
});
li.removeEventListener('click', func);
}
এবং এখানে আমাদের সমাধান আরেকটি সমস্যার সৃষ্টি করে। ব্যাপারটি হল যে ইভেন্ট হ্যান্ডলারে প্যারামিটার পাঠানো এত সহজ নয়:
for (let li of lis) {
li.addEventListener('click', func(li)); // কাজ করে না!
}
এই সমস্যা সমাধানের জন্য আমরা কেবল একটি anonymus হ্যান্ডলারের ভিতরে আমাদের ফাংশনটি কল করব:
for (let li of lis) {
li.addEventListener('click', function() {
func(li);
});
}
এবং একইভাবে নতুন তালিকা আইটেম তৈরি করার সময় কাজ করব:
adder.addEventListener('blur', function() {
let li = document.createElement('li');
li.textContent = this.value;
li.addEventListener('click', function() {
func(li);
});
ul.append(li);
});
তৃতীয় সমাধান
একটি আরও মার্জিত সমাধান আছে। আপনি কেবল ডেলিগেশন ব্যবহার করতে পারেন। এই ক্ষেত্রে নতুন তালিকা আইটেমের সমস্যা সৃষ্টিই হবে না:
ul.addEventListener('click', function(event) {
if (event.target.tagName === 'LI') { // আমরা ঠিক li-তে ক্লিক ধরি, ইনপুটে নয়
let li = event.target;
let input = document.createElement('input');
input.value = li.textContent;
li.textContent = '';
li.append(input);
input.addEventListener('blur', function() {
li.textContent = this.value;
});
}
});
এই ক্ষেত্রে তালিকা আইটেমগুলির উপর লুপ আমাদের সাধারণত প্রয়োজন হবে না, এবং নতুন তালিকা আইটেম তৈরি করার কোড এতটাই সংক্ষিপ্ত হবে:
adder.addEventListener('blur', function() {
let li = document.createElement('li');
li.textContent = this.value;
ul.append(li);
});