Reputation: 17422
I know that jquery or zepto $(selctor).on(event, handler)
will trigger events of dynamic created elements. But I don't use jquery and zepto.I'd like write my code from scratch for both learning and lightweigh.
There are lots of sth.innerHTML=blabla
and sth.appendChild(..)
snippets in my codes. I have to bind event to them.
I want a simple function like this,
function $on(selector, eventType, handler) {
document.querySelectAll(selector).forEach(function(el) {
el.addEventListener(eventType, handler);
});
// on new DOM insert or replaced, let us call it newDom
newDom.querySelectAll(selector).forEach(function(el) {
el.addEventListener(eventType, handler);
});
}
but I don't know if jquery work like this, I want to know it, and complete my function.
Upvotes: 1
Views: 684
Reputation: 135357
Here's an example using the newer MutationObserver recommended by the MDN docs.
This depends on Element.prototype.matches which is not widely supported yet. However, I created a little wrapper to make it easier to work with.
// live listener function
(function(window) {
// Element.matches "polyfill"
(function(e){
if (typeof e.matches !== "function") {
e.matches = e.webkitMatchesSelector ||
e.mozMatchesSelector ||
e.msMatchesSelector ||
e.oMatchesSelector ||
e.matchesSelector;
}
})(Element.prototype);
function on(selector, eventType, handler) {
// add listener for all existing elements
[].forEach.call(document.querySelectorAll(selector), function(elem) {
elem.addEventListener(eventType, handler);
});
// create new "live" observer
var observer = new MutationObserver(function(records) {
records.forEach(function(record) {
[].forEach.call(record.addedNodes || [], function(elem) {
if (elem.matches(selector)) {
elem.addEventListener(eventType, handler);
}
});
});
});
// watch for DOM changes to body's children and body's subtree
observer.observe(document.body, {
childList: true,
subtree: true
});
return observer;
}
window.on = on;
})(window);
Let's create some elements
// sample button generator
function createButton() {
var b = document.createElement("button");
b.className = "hello";
b.innerHTML = "Spaghett";
document.body.appendChild(b);
}
// create a new button every second
setInterval(createButton, 1000);
Actual usage
on("button.hello", "click", function(event) {
alert("spooked ya!");
event.preventDefault();
});
Notable notes!
I'm using [].forEach.call(..., fn)
because querySelectorAll
does not return an Array
. Instead, it returns a NodeList. A NodeList object does not have Array.prototype in its prototype chain and therefore does not have direct access to the .forEach function. MutationRecord.prototype.addedNodes also returns a NodeList.
Upvotes: 5