DOM elementlerini redakte etmek funksiyasinin tekrarlanmasi xetasi JavaScript-də
Tutaq ki, bizim müəyyən bir siyahımız var:
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
Siyahının özünü və onun bəndlərini ayrı-ayrı dəyişənlərə alaq:
let ul = document.querySelector('ul');
let lis = document.querySelectorAll('li');
Gəlin edək ki, siyahımızın bəndləri yaradılan input ilə redaktə oluna bilsin:
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);
});
}
Tutaq ki, indi biz istəyirik ki, siyahıya yeni bəndlər əlavə etmək mümkün olsun. Bunun üçün siyahının altında müvafiq input olsun:
<input id="adder">
Bu inputa istinadı dəyişənə alaq:
let adder = document.querySelector('#adder');
Gəlin edək ki, inputun fokus itkisi zamanı siyahıya inputdan götürülmüş mətnlə yeni bənd əlavə olunsun:
adder.addEventListener('blur', function() {
let li = document.createElement('li');
li.textContent = this.value;
ul.append(li);
});
Tutaq ki, indi biz istəyirik ki, yeni əlavə edilmiş bəndlər də redaktə oluna bilsin. Öz-özünə onlar üçün redaktə işləməyəcək, çünki biz siyahı bəndlərinə klik işləyicisini qoyanda, bu bəndlər hələ yox idi.
Gəlin bu problemin mümkün həll variantlarına baxaq.
Birinci həll
Ən sadə həll - func funksiyasının
kodunu təkrarlamaqdır, onu
yeni yaradılmış bəndlər üçün də tətbiq etməklə:
adder.addEventListener('blur', function() {
let li = document.createElement('li');
li.textContent = this.value;
li.addEventListener('click', function func() {
// burada kodu təkrarlayırıq
});
ul.append(li);
});
Əlbəttə, bu həlldə biz dərhal çatışmazlığı görürük - kodu təkrarlamaq düzgün deyil.
İkinci həll
Təkrarlanma problemini həll etmək üçün
məntiqli func funksiyasını
kənara çıxarmaq, onu Function Declaration etməkdir:
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);
}
Bizi problem burada gözləyir.
Məsələ ondadır ki, bizim funksiya
xarici görünmə sahəsindən alınan
li dəyişənindən istifadə edirdi.
Amma funksiyanı kənara çıxardıqdan sonra bu
dəyişən artıq görünmür!
Problemi həll etmək üçün
bizim li-i parametr kimi ötürək:
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);
}
Və burada bizim həll daha bir problem yaradır. Məsələ ondadır ki, hadisə işləyicisinə parametri sadəcə ötürmək olmaz:
for (let li of lis) {
li.addEventListener('click', func(li)); // işləmir!
}
Bu problemi həll etmək üçün sadəcə bizim funksiyanı anonim işləyici daxilində çağıraq:
for (let li of lis) {
li.addEventListener('click', function() {
func(li);
});
}
Və eyni şəkildi yeni siyahı bəndi yaradarkən də edək:
adder.addEventListener('blur', function() {
let li = document.createElement('li');
li.textContent = this.value;
li.addEventListener('click', function() {
func(li);
});
ul.append(li);
});
Üçüncü həll
Daha zərif bir həll mövcuddur. Sadəcə delegasiyadan istifadə etmək olar. Bu halda yeni siyahı bəndləri ilə problem ümumiyyətlə yaranmayacaq:
ul.addEventListener('click', function(event) {
if (event.target.tagName === 'LI') { // xüsusilə li üzərində kliki tuturuq, input üzərində yox
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;
});
}
});
Bu halda siyahı bəndləri üzrə dövrə ümumiyyətlə ehtiyacımız olmayacaq, və kod yeni siyahı bəndi yaratmaq üçün belə qısaldılacaq:
adder.addEventListener('blur', function() {
let li = document.createElement('li');
li.textContent = this.value;
ul.append(li);
});