17 of 17 menu

Fejl ved duplikering af funktion til redigering af DOM-elementer i JavaScript

Lad os sige, at vi har en liste:

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

Lad os hente selve listen og dens punkter i separate variable:

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

Lad os gøre det således, at punkterne i vores liste kan redigeres med et input-felt, der popper op:

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); }); }

Lad os nu sige, at vi ønsker at kunne tilføje nye punkter til listen. Lad os til dette have et tilsvarende input-felt under listen:

<input id="adder">

Lad os hente en reference til dette input-felt i en variabel:

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

Lad os gøre det således, at ved tab af fokus på input-feltet tilføjes et nyt punkt til listen med teksten, hentet fra vores input-felt:

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

Lad os nu sige, at vi ønsker, at de nyligt tilføjede punkter også kan redigeres. Det vil ikke fungere af sig selv for dem, fordi da vi tilføjede click-event-handleren på listepunkterne, eksisterede disse punkter endnu ikke.

Lad os se på de mulige løsninger på dette problem.

Første løsning

Den enkleste løsning er at duplikere koden for funktionen func og tilknytte den også for de nyligt oprettede punkter:

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

Selvfølgelig ser vi straks en ulempe ved denne løsning - det er ikke korrekt at duplikere kode.

Anden løsning

For at løse duplikeringsproblemet er det logisk at flytte funktionen func ud og gøre den til en Function Declaration:

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); }

Her venter problemet på os. Problemet er, at vores funktion brugte variablen li, som blev hentet fra det ydre scope. Men efter at have flyttet funktionen er denne variabel nu ikke længere synlig!

For at løse problemet vil vi sende vores li som en parameter:

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); }

Og her skaber vores løsning endnu et problem. Problemet er, at man ikke bare kan sende en parameter til en event-handler:

for (let li of lis) { li.addEventListener('click', func(li)); // virker ikke! }

For at løse dette problem kan vi blot kalde vores funktion inde i en anonym event-handler:

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

Og vi gør på samme måde, når vi opretter et nyt listepunkt:

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

Tredje løsning

Der findes en mere elegant løsning. Man kan simpelthen bruge delegation. I dette tilfælde opstår problemet med nye punkter i listen slet ikke:

ul.addEventListener('click', function(event) { if (event.target.tagName === 'LI') { // fanger specifikt klik på li, ikke på 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; }); } });

I dette tilfælde har vi slet ikke brug for en løkke over listepunkterne, og koden for at oprette et nyt listepunkt bliver reduceret til dette:

adder.addEventListener('blur', function() { let li = document.createElement('li'); li.textContent = this.value; ul.append(li); });
Dansk
AfrikaansAzərbaycanБългарскиবাংলাБеларускаяČeštinaDeutschΕλληνικάEnglishEspañolEestiSuomiFrançaisहिन्दीMagyarՀայերենIndonesiaItaliano日本語ქართულიҚазақ한국어КыргызчаLietuviųLatviešuМакедонскиMelayuမြန်မာNederlandsNorskPolskiPortuguêsRomânăРусскийසිංහලSlovenčinaSlovenščinaShqipСрпскиSrpskiSvenskaKiswahiliТоҷикӣไทยTürkmenTürkçeЎзбекOʻzbekTiếng Việt
Vi bruger cookies til webstedets funktion, analyse og personalisering. Behandling af data foregår i henhold til Fortrolighedspolitikken.
accepter alle tilpas afvis