17 of 17 menu

Erro de duplicação de função de edição de elementos DOM em JavaScript

Suponha que temos uma lista:

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

Vamos obter a própria lista e seus itens em variáveis separadas:

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

Vamos fazer com que os itens da nossa lista possam ser editados por um input que aparece:

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

Suponha agora que queremos que novos itens possam ser adicionados à lista. Suponha que para isso tenhamos um input correspondente abaixo da lista:

<input id="adder">

Vamos obter a referência para este input em uma variável:

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

Vamos fazer com que, ao perder o foco, o input adicione um novo item à lista com o texto obtido do nosso input:

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

Suponha agora que queremos que os itens recém-adicionados também possam ser editados. Por si só, a edição não funcionará para eles, pois quando anexamos o manipulador de clique aos itens da lista, esses itens ainda não existiam.

Vamos ver as possíveis variantes de solução para este problema.

Solução um

A solução mais simples é duplicar o código da função func, vinculando-a também para os itens recém-criados:

adder.addEventListener('blur', function() { let li = document.createElement('li'); li.textContent = this.value; li.addEventListener('click', function func() { // aqui duplicamos o código }); ul.append(li); });

Claro, nesta solução vemos imediatamente a desvantagem - duplicar código não é correto.

Solução dois

Para resolver o problema da duplicação, é lógico colocar a função func para fora, tornando-a uma 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); }

Aqui é onde o problema nos espera. O fato é que nossa função usava a variável li, obtida do escopo externo. Mas depois de colocar a função para fora, essa variável agora não é visível!

Para resolver o problema, vamos passar nossa li como parâmetro:

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

E aqui nossa solução gera mais um problema. O fato é que não se pode simplesmente passar um parâmetro para um manipulador de evento:

for (let li in lis) { li.addEventListener('click', func(li)); // não funciona! }

Para resolver este problema, basta chamar nossa função dentro de um manipulador anônimo:

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

E agir de forma análoga ao criar um novo item de lista:

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

Solução três

Existe uma solução mais elegante. Podemos simplesmente usar a delegação de eventos. Neste caso, o problema com os novos itens de lista simplesmente não surgirá:

ul.addEventListener('click', function(event) { if (event.target.tagName === 'LI') { // capturamos exatamente o clique no li, não no 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; }); } });

Neste caso, o loop pelos itens da lista nem será necessário, e o código para criar um novo item de lista se reduzirá a isto:

adder.addEventListener('blur', function() { let li = document.createElement('li'); li.textContent = this.value; ul.append(li); });
Português
AfrikaansAzərbaycanБългарскиবাংলাБеларускаяČeštinaDanskDeutschΕλληνικάEnglishEspañolEestiSuomiFrançaisहिन्दीMagyarՀայերենIndonesiaItaliano日本語ქართულიҚазақ한국어КыргызчаLietuviųLatviešuМакедонскиMelayuမြန်မာNederlandsNorskPolskiRomânăРусскийසිංහලSlovenčinaSlovenščinaShqipСрпскиSrpskiSvenskaKiswahiliТоҷикӣไทยTürkmenTürkçeЎзбекOʻzbekTiếng Việt
Nós usamos cookies para o funcionamento do site, análises e personalização. O processamento de dados é realizado de acordo com a Política de Privacidade.
aceitar todas configurar rejeitar