Estoy tratando de agregar un detector de eventos de clic a un grupo de divs recién creados en un bucle for. El problema que tengo es que solo el último div mantiene su detector de eventos. He leído sobre cierres y he leído varias otras publicaciones y preguntas y sus respuestas, y por lo que puedo decir, lo tengo configurado correctamente. Pero todavía no funciona para mí. Solo el div final que se va a iterar recibe el detector de eventos.
function edit_entry(k) { wrd_input.value = k; def_input.value = lexicon[k][1]; wrd_input.onkeyup(); delete lexicon[k]; rewrite_entries(); } function rewrite_entries(keys = null) { if (keys === null) { keys = []; } let sorted_keys = sort_lex_keys(); lex_body.style.color = 'rgb(200, 200, 200)'; lex_body.innerHTML = ''; sorted_keys.forEach((key) => { if (!keys.length || keys.includes(key)) { lex_body.innerHTML += `<div class='lex-entry' id=${key}><i>${key}</i>\n<p class='pronunciation'>${lexicon[key][0]}</p>${lexicon[key][1]}</div>\n`; let entry = document.getElementById(key) entry.addEventListener('click', edit_entry.bind(this, key) ); } }); }Estado actual del código relevante anterior. Si alguien conoce el problema, sería de gran ayuda. Si es relevante, este código se ejecuta a través de Electron (17.0.0).
Un intento de solución, utilizando una función de flecha anónima en lugar de un enlace:
entry.addEventListener('click', () => edit_entry(key) );da el mismo resultado.
Actualización: cambiar el atributo .innerHTML de algo aparentemente elimina todos los detectores de eventos. Entonces, la solución fue simplemente crear el elemento completamente en js, agregarlo al contenedor y luego agregar el oyente. Este cambio en el bucle forEach resuelve el problema:
sorted_keys.forEach((key) => { if (!keys.length || keys.includes(key)) { let entry = document.createElement('div'); entry.className = 'lex-entry'; let word = document.createElement('p'); word.appendChild( document.createTextNode(key) ); word.style.fontStyle = 'italic'; let pron = document.createElement('p'); pron.className = 'pronunciation'; pron.appendChild( document.createTextNode(lexicon[key][0]) ); let defn = document.createTextNode(lexicon[key][1]); entry.append(word, pron, defn); entry.addEventListener('click', () => edit_entry(key) ); lex_body.appendChild(entry);Así que algunas cosas se me pasan por la cabeza:
En primer lugar, edit_entry.bind(this, key); : ¿Estás seguro de que this apunta a lo que quieres? Debería estar apuntando al objeto de la window . Además, ¿hay alguna razón para vincular el contexto para esa función en particular?
En segundo lugar, innerHTML : generalmente se desaconseja usar innerHTML directamente. No sé cómo/cuándo los diseños del navegador cambian a innerHTML , es posible que el div no esté en la página cuando llamas a getElementById . Como alternativa, puede probar document.createElement("div") , establecer sus propiedades en consecuencia y finalmente agregarlo a lex_body .
Editar
Desde mdn :
Tenga en cuenta que el uso de innerHTML para agregar elementos html (p. ej., el.innerHTML += "enlace") dará como resultado la eliminación de cualquier detector de eventos establecido previamente. Es decir, después de agregar cualquier elemento HTML de esa manera, no podrá escuchar los detectores de eventos establecidos previamente.
Creo que vincular la función cada vez con this anula el enlace cada vez, esa debería ser la razón por la que solo obtiene el último evento.
Dentro de forEach lambda, la palabra clave this se refiere a la clase interna que llama a forEach no a su función rewrite_entries . Intenta no vincular la llamada, así:
entry.addEventListener('click', () => edit_entry(key) );