Я пытаюсь динамически вставлять данные html в список, который создается динамически, но когда я пытаюсь прикрепить событие onclick для кнопки, которая создается динамически, событие не запускается. Решение было бы очень признательно.
Код 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);
});
});
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
Манджу
источник
источник
Ответы:
Это связано с тем, что ваш элемент создается динамически. Для обработки события следует использовать делегирование события.
document.addEventListener('click',function(e){ if(e.target && e.target.id== 'brnPrepend'){ //do something } });
jquery упрощает:
$(document).on('click','#btnPrepend',function(){//do something})
Вот статья о делегировании событий Статья о делегировании событий
источник
Существует обходной путь: фиксирует клики
document.body
и затем проверяет цель события.document.body.addEventListener( 'click', function ( event ) { if( event.srcElement.id == 'btnSubmit' ) { someFunc(); }; } );
источник
Вы должны присоединить событие после вставленных элементов, например, вы не присоединяете глобальное событие к своему,
document
а к конкретному событию для вставленных элементов.например
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>
источник
javascript document.addEventListener('click',function(e){ if(e.target && e.target.id== 'brnPrepend'){ //do something } });
Разница в том, как вы создаете и добавляете элементы в DOM.
Если вы создаете элемент через
document.createElement
, добавьте прослушиватель событий и добавьте его в DOM. Ваши события загорятся.Если вы создаете элемент в виде строки, например: html + = "<li> test </li>" `, элемент технически представляет собой просто строку. Строки не могут иметь прослушивателей событий.
Одно из решений - создать каждый элемент,
document.createElement
а затем напрямую добавить его в элемент DOM.// Sample let li = document.createElement('li') document.querySelector('ul').appendChild(li)
источник
Вы можете сделать что-то подобное:
// 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);
источник
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; }
Теперь вы можете зарегистрировать событие, например,
_( document ).on( "click", "#brnPrepend", function( _event, _element ){ console.log( _event ); console.log( _element ); // Todo });
Поддержка браузера
Chrome - 4.0, Edge - 9.0, Firefox - 3.5 Safari - 3.2, Opera - 10.0 и выше
источник
Я создал небольшую библиотеку, чтобы помочь с этим: Источник библиотеки на 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>
Функциональность аналогична jQuery.on ().
Библиотека использует метод Element.matches () для проверки целевого элемента на соответствие заданному селектору. Когда событие запускается, обратный вызов вызывается только в том случае, если целевой элемент соответствует заданному селектору.
источник
Я знаю, что тема слишком старая, но я дал себе несколько минут, чтобы создать очень полезный код, который отлично работает и очень легко работает с pure
JAVASCRIPT
. Вот код с простым примером: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>
источник
Я сделал для этого простую функцию.
_case
Функция позволяет не только получить цель, но и получить родительский элемент , где вы связать мероприятие.Функция обратного вызова возвращает событие, которое содержит target (
evt.target
) и родительский элемент, соответствующий селектору (this
). Здесь вы можете делать то, что вам нужно, после нажатия на элемент.Я еще не решил, что лучше,
if-else
илиswitch
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>
Надеюсь, это поможет!
источник
Я обнаружил, что решение, опубликованное jillykate, работает, но только в том случае, если целевой элемент является наиболее вложенным. Если это не так, это можно исправить, перебирая родителей, т. Е.
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);
Также обратите внимание, что мы можем обрабатывать события по любому атрибуту или прикреплять нашего слушателя на любом уровне. В приведенном выше коде используется настраиваемый атрибут и
window
. Я сомневаюсь, что между различными методами есть какая-то прагматическая разница.источник