17 of 17 menu

Erreur de duplication de fonction d'édition d'éléments DOM en JavaScript

Supposons que nous ayons une certaine liste :

<ul> <li>1</li> <li>2</li> <li>3</li> </ul>

Récupérons la liste elle-même et ses éléments dans des variables séparées :

let ul = document.querySelector('ul'); let lis = document.querySelectorAll('li');

Faisons en sorte que les éléments de notre liste puissent être édités via un champ de saisie qui apparaît :

for (let li of lis) { li.addEventListener('click', function func() { let input = document.createElement('input'); input.value = list.textContent; li.textContent = ''; li.append(input); input.addEventListener('blur', function() { li.textContent = this.value; li.addEventListener('click', func); }); li.removeEventListener('click', func); }); }

Supposons maintenant que nous voulons pouvoir ajouter de nouveaux éléments à la liste. Pour cela, supposons que nous ayons un champ de saisie correspondant sous la liste :

<input id="adder">

Récupérons une référence à ce champ de saisie dans une variable :

let adder = document.querySelector('#adder');

Faisons en sorte qu'à la perte du focus du champ de saisie, un nouvel élément soit ajouté à la liste avec le texte pris de notre champ de saisie :

adder.addEventListener('blur', function() { let li = document.createElement('li'); li.textContent = this.value; ul.append(li); });

Supposons maintenant que nous voulons que les éléments nouvellement ajoutés puissent également être édités. En soi, l'édition ne fonctionnera pas pour eux, car lorsque nous avons attaché le gestionnaire de clic aux éléments de la liste, ces éléments n'existaient pas encore.

Examinons les différentes options possibles pour résoudre ce problème.

Première solution

La solution la plus simple est de dupliquer le code de la fonction func, en la liant également pour les éléments nouvellement créés :

adder.addEventListener('blur', function() { let li = document.createElement('li'); li.textContent = this.value; li.addEventListener('click', function func() { // ici nous dupliquons le code }); ul.append(li); });

Bien sûr, dans cette solution, nous voyons immédiatement l'inconvénient - dupliquer le code n'est pas correct.

Deuxième solution

Pour résoudre le problème de duplication, il est logique d'extraire la fonction func vers l'extérieur, en en faisant une Function Declaration :

function func() { let input = document.createElement('input'); input.value = list.textContent; li.textContent = ''; li.append(input); input.addEventListener('blur', function() { li.textContent = this.value; li.addEventListener('click', func); }); li.removeEventListener('click', func); }

C'est ici que nous rencontrons le problème. Le fait est que notre fonction utilisait la variable li, obtenue depuis la portée externe. Mais après l'extraction de la fonction, cette variable n'est maintenant plus visible !

Pour résoudre le problème, nous allons passer notre li en paramètre :

function func(li) { let input = document.createElement('input'); input.value = list.textContent; li.textContent = ''; li.append(input); input.addEventListener('blur', function() { li.textContent = this.value; li.addEventListener('click', func); }); li.removeEventListener('click', func); }

Et ici, notre solution génère un autre problème. Le fait est que l'on ne peut pas simplement passer un paramètre au gestionnaire d'événement :

for (let li in lis) { li.addEventListener('click', func(li)); // ne fonctionne pas ! }

Pour résoudre ce problème, nous allons simplement appeler notre fonction à l'intérieur d'un gestionnaire anonyme :

for (let li of lis) { li.addEventListener('click', function() { func(li); }); }

Et nous procéderons de manière similaire lors de la création d'un nouvel élément de liste :

adder.addEventListener('blur', function() { let li = document.createElement('li'); li.textContent = this.value; li.addEventListener('click', function() { func(li); }); ul.append(li); });

Troisième solution

Il existe une solution plus élégante. On peut simplement utiliser la délégation d'événements. Dans ce cas, le problème avec les nouveaux éléments de liste ne se posera simplement pas :

ul.addEventListener('click', function(event) { if (event.target.tagName === 'LI') { // nous capturons précisément le clic sur li, pas sur input 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; }); } });

Dans ce cas, la boucle sur les éléments de la liste ne nous sera généralement plus nécessaire, et le code pour créer un nouvel élément de liste se réduira à ceci :

adder.addEventListener('blur', function() { let li = document.createElement('li'); li.textContent = this.value; ul.append(li); });
Français
AfrikaansAzərbaycanБългарскиবাংলাБеларускаяČeštinaDanskDeutschΕλληνικάEnglishEspañolEestiSuomiहिन्दीMagyarՀայերենIndonesiaItaliano日本語ქართულიҚазақ한국어КыргызчаLietuviųLatviešuМакедонскиMelayuမြန်မာNederlandsNorskPolskiPortuguêsRomânăРусскийසිංහලSlovenčinaSlovenščinaShqipСрпскиSrpskiSvenskaKiswahiliТоҷикӣไทยTürkmenTürkçeЎзбекOʻzbekTiếng Việt
Nous utilisons des cookies pour le fonctionnement du site, l'analyse et la personnalisation. Le traitement des données est effectué conformément à la Politique de confidentialité.
accepter tout personnaliser refuser