Estoy tratando de insertar datos html dinámicamente en una lista que se crea dinámicamente, pero cuando intento adjuntar un evento onclick para el botón que se crea dinámicamente, el evento no se activa. La solución sería muy apreciada.
Código Javascript:
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('btnSubmit').addEventListener('click', function () {
var name = document.getElementById('txtName').value;
var mobile = document.getElementById('txtMobile').value;
var html = '<ul>';
for (i = 0; i < 5; i++) {
html = html + '<li>' + name + i + '</li>';
}
html = html + '</ul>';
html = html + '<input type="button" value="prepend" id="btnPrepend" />';
document.getElementsByTagName('form')[0].insertAdjacentHTML('afterend', html);
});
document.getElementById('btnPrepend').addEventListener('click', function () {
var html = '<li>Prepending data</li>';
document.getElementsByTagName('ul')[0].insertAdjacentHTML('afterbegin', html);
});
});
Código HTML:
<form>
<div class="control">
<label>Name</label>
<input id="txtName" name="txtName" type="text" />
</div>
<div class="control">
<label>Mobile</label>
<input id="txtMobile" type="text" />
</div>
<div class="control">
<input id="btnSubmit" type="button" value="submit" />
</div>
</form>
javascript
Manju
fuente
fuente
Respuestas:
Esto se debe al hecho de que su elemento se crea dinámicamente. Debe usar la delegación de eventos para manejar el evento.
document.addEventListener('click',function(e){ if(e.target && e.target.id== 'brnPrepend'){ //do something } });
jquery lo hace más fácil:
$(document).on('click','#btnPrepend',function(){//do something})
Aquí hay un artículo sobre delegación de eventos artículo de delegación de eventos
fuente
Existe una solución al capturar los clics
document.body
y luego verificar el destino del evento.document.body.addEventListener( 'click', function ( event ) { if( event.srcElement.id == 'btnSubmit' ) { someFunc(); }; } );
fuente
Debe adjuntar el evento después de insertar elementos, así no adjunta un evento global en su
document
sino un evento específico en los elementos insertados.p.ej
document.getElementById('form').addEventListener('submit', function(e) { e.preventDefault(); var name = document.getElementById('txtName').value; var idElement = 'btnPrepend'; var html = ` <ul> <li>${name}</li> </ul> <input type="button" value="prepend" id="${idElement}" /> `; /* Insert the html into your DOM */ insertHTML('form', html); /* Add an event listener after insert html */ addEvent(idElement); }); const insertHTML = (tag = 'form', html, position = 'afterend', index = 0) => { document.getElementsByTagName(tag)[index].insertAdjacentHTML(position, html); } const addEvent = (id, event = 'click') => { document.getElementById(id).addEventListener(event, function() { insertHTML('ul', '<li>Prepending data</li>', 'afterbegin') }); }
<form id="form"> <div> <label for="txtName">Name</label> <input id="txtName" name="txtName" type="text" /> </div> <input type="submit" value="submit" /> </form>
fuente
javascript document.addEventListener('click',function(e){ if(e.target && e.target.id== 'brnPrepend'){ //do something } });
La diferencia está en cómo crea y agrega elementos en el DOM.
Si crea un elemento a través de
document.createElement
, agregue un detector de eventos y añádalo al DOM. Tus eventos se dispararán.Si crea un elemento como una cadena como esta: html + = "<li> test </li>" `, el elemento es técnicamente solo una cadena. Las cadenas no pueden tener detectores de eventos.
Una solución es crear cada elemento con
document.createElement
y luego agregarlos a un elemento DOM directamente.// Sample let li = document.createElement('li') document.querySelector('ul').appendChild(li)
fuente
Puedes hacer algo similar a esto:
// Get the parent to attatch the element into var parent = document.getElementsByTagName("ul")[0]; // Create element with random id var element = document.createElement("li"); element.id = "li-"+Math.floor(Math.random()*9999); // Add event listener element.addEventListener("click", EVENT_FN); // Add to parent parent.appendChild(element);
fuente
var __ = function(){ this.context = []; var self = this; this.selector = function( _elem, _sel ){ return _elem.querySelectorAll( _sel ); } this.on = function( _event, _element, _function ){ this.context = self.selector( document, _element ); document.addEventListener( _event, function(e){ var elem = e.target; while ( elem != null ) { if( "#"+elem.id == _element || self.isClass( elem, _element ) || self.elemEqal( elem ) ){ _function( e, elem ); } elem = elem.parentElement; } }, false ); }; this.isClass = function( _elem, _class ){ var names = _elem.className.trim().split(" "); for( this.it = 0; this.it < names.length; this.it++ ){ names[this.it] = "."+names[this.it]; } return names.indexOf( _class ) != -1 ? true : false; }; this.elemEqal = function( _elem ){ var flg = false; for( this.it = 0; this.it < this.context.length; this.it++ ){ if( this.context[this.it] === _elem && !flg ){ flg = true; } } return flg; }; } function _( _sel_string ){ var new_selc = new __( _sel_string ); return new_selc; }
Ahora puedes registrar eventos como,
_( document ).on( "click", "#brnPrepend", function( _event, _element ){ console.log( _event ); console.log( _element ); // Todo });
Soporte del navegador
chrome - 4.0, Edge - 9.0, Firefox - 3.5 Safari - 3.2, Opera - 10.0 y superior
fuente
He creado una pequeña biblioteca para ayudar con esto: Fuente de la biblioteca en GitHub
<script src="dynamicListener.min.js"></script> <script> // Any `li` or element with class `.myClass` will trigger the callback, // even elements created dynamically after the event listener was created. addDynamicEventListener(document.body, 'click', '.myClass, li', function (e) { console.log('Clicked', e.target.innerText); }); </script>
La funcionalidad es similar a jQuery.on ().
La biblioteca usa el método Element.matches () para probar el elemento de destino con el selector dado. Cuando se activa un evento, la devolución de llamada solo se llama si el elemento de destino coincide con el selector dado.
fuente
Sé que el tema es demasiado antiguo, pero me di unos minutos para crear un código muy útil que funciona bien y es muy fácil de usar puro
JAVASCRIPT
. Aquí está el código con un ejemplo simple:String.prototype.addEventListener=function(eventHandler, functionToDo){ let selector=this; document.body.addEventListener(eventHandler, function(e){ e=(e||window.event); e.preventDefault(); const path=e.path; path.forEach(function(elem){ const selectorsArray=document.querySelectorAll(selector); selectorsArray.forEach(function(slt){ if(slt==elem){ if(typeof functionToDo=="function") functionToDo(el=slt, e=e); } }); }); }); } // And here is how we can use it actually ! "input[type='number']".addEventListener("click", function(element, e){ console.log( e ); // Console log the value of the current number input });
<input type="number" value="25"> <br> <input type="number" value="15"> <br><br> <button onclick="addDynamicInput()">Add a Dynamic Input</button> <script type="text/javascript"> function addDynamicInput(){ const inpt=document.createElement("input"); inpt.type="number"; inpt.value=Math.floor(Math.random()*30+1); document.body.prepend(inpt); } </script>
fuente
Hice una función simple para esto.
La
_case
función le permite no solo obtener el objetivo, sino también obtener el elemento padre donde vincula el evento.La función de devolución de llamada devuelve el evento que contiene el objetivo (
evt.target
) y el elemento principal que coincide con el selector (this
). Aquí puede hacer las cosas que necesita después de hacer clic en el elemento.Aún no he decidido cuál es mejor, el
if-else
o elswitch
var _case = function(evt, selector, cb) { var _this = evt.target.closest(selector); if (_this && _this.nodeType) { cb.call(_this, evt); return true; } else { return false; } } document.getElementById('ifelse').addEventListener('click', function(evt) { if (_case(evt, '.parent1', function(evt) { console.log('1: ', this, evt.target); })) return false; if (_case(evt, '.parent2', function(evt) { console.log('2: ', this, evt.target); })) return false; console.log('ifelse: ', this); }) document.getElementById('switch').addEventListener('click', function(evt) { switch (true) { case _case(evt, '.parent3', function(evt) { console.log('3: ', this, evt.target); }): break; case _case(evt, '.parent4', function(evt) { console.log('4: ', this, evt.target); }): break; default: console.log('switch: ', this); break; } })
#ifelse { background: red; height: 100px; } #switch { background: yellow; height: 100px; }
<div id="ifelse"> <div class="parent1"> <div class="child1">Click me 1!</div> </div> <div class="parent2"> <div class="child2">Click me 2!</div> </div> </div> <div id="switch"> <div class="parent3"> <div class="child3">Click me 3!</div> </div> <div class="parent4"> <div class="child4">Click me 4!</div> </div> </div>
¡Espero eso ayude!
fuente
He encontrado que la solución publicada por jillykate funciona, pero solo si el elemento de destino es el más anidado. Si este no es el caso, esto se puede rectificar iterando sobre los padres, es decir
function on_window_click(event) { let e = event.target; while (e !== null) { // --- Handle clicks here, e.g. --- if (e.getAttribute(`data-say_hello`)) { console.log("Hello, world!"); } e = e.parentElement; } } window.addEventListener("click", on_window_click);
También tenga en cuenta que podemos manejar eventos por cualquier atributo, o adjuntar nuestro oyente en cualquier nivel. El código anterior usa un atributo personalizado y
window
. Dudo que haya alguna diferencia pragmática entre los distintos métodos.fuente