This post looks at a custom event handler that I wrote using vanilla JS for a project a few weeks ago. The project could not use any additional plugins such as jQuery, as the overheads had to be minimised. Therefore I needed a solution which enabled me to dynamically add elements to the DOM, without having to attach event listeners every time.
The function dependency for this handler is querySelectorAll(), this function is supported in browsers from IE8 upwards. However, for further backwards compatibility (IE6/7) a polyfill like this one would be required; I chose not to include the polyfill in the code below as other plugins are often better suited at accomplishing this, such as yepnope and has.js. Additionally, Chrome and Firefox ship with their own selector function and the script takes full advantage of these functions when they are available – falling back to my own matcher function if they are not.
(function(t) { window.delegate = function(selector, event, handler) { var fnc = function(e) { var src = e.target || e.srcElement; var matcher = src.webkitMatchesSelector || src.mozMatchesSelector || function(selector) { var elements = document.querySelectorAll(selector); for (var i in elements) { if (elements[i] === this) { return true; } } return false; }; while (src !== document) { var match = matcher.call(src, selector); if (match) { handler.call(src, e); break; } src = src.parentNode; } }; var handle = document; if (selector === window) { handle = window; fnc = handler; } if (handle.addEventListener) { return handle.addEventListener(event, fnc); } else { return handle.attachEvent("on" + event, fnc); } } }());
I have also written a modular Coffeescript version of this event handler, available here.
The script is also able to correctly propagate events, such that if a click event is bound to a parent element, and one of its child elements is clicked, aslong as that element has no event itself, the event will bubble up properly and subsequently fire for the container element.