Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><strong>Updated Answer</strong></p> <p>jQuery changed the location of where events are stored in 1.8. Now you know why it is such a bad idea to mess around with internal APIs :)</p> <p>The new <strong><em>internal</em></strong> API to access to events for a DOM object is available through the global jQuery object, and not tied to each instance, and it takes a DOM element as the first parameter, and a key ("events" for us) as the second parameter.</p> <pre><code>jQuery._data(&lt;DOM element&gt;, "events"); </code></pre> <p>So here's the modified code for jQuery 1.8.</p> <pre><code>// [name] is the name of the event "click", "mouseover", .. // same as you'd pass it to bind() // [fn] is the handler function $.fn.bindFirst = function(name, fn) { // bind as you normally would // don't want to miss out on any jQuery magic this.on(name, fn); // Thanks to a comment by @Martin, adding support for // namespaced events too. this.each(function() { var handlers = $._data(this, 'events')[name.split('.')[0]]; // take out the handler we just inserted from the end var handler = handlers.pop(); // move it at the beginning handlers.splice(0, 0, handler); }); }; </code></pre> <p>And here's a <a href="http://jsfiddle.net/x8Na8/2/" rel="noreferrer">playground</a>.</p> <hr /> <p><strong>Original Answer</strong></p> <p>As @Sean has discovered, jQuery exposes all event handlers through an element's <code>data</code> interface. Specifically <code>element.data('events')</code>. Using this you could always write a simple plugin whereby you could insert any event handler at a specific position.</p> <p>Here's a simple plugin that does just that to insert a handler at the beginning of the list. You can easily extend this to insert an item at any given position. It's just array manipulation. But since I haven't seen jQuery's source and don't want to miss out on any jQuery magic from happening, I normally add the handler using <code>bind</code> first, and then reshuffle the array.</p> <pre><code>// [name] is the name of the event "click", "mouseover", .. // same as you'd pass it to bind() // [fn] is the handler function $.fn.bindFirst = function(name, fn) { // bind as you normally would // don't want to miss out on any jQuery magic this.bind(name, fn); // Thanks to a comment by @Martin, adding support for // namespaced events too. var handlers = this.data('events')[name.split('.')[0]]; // take out the handler we just inserted from the end var handler = handlers.pop(); // move it at the beginning handlers.splice(0, 0, handler); }; </code></pre> <p>So for example, for this markup it would work as (<a href="http://jsfiddle.net/j6HP5/2/" rel="noreferrer">example here</a>):</p> <pre><code>&lt;div id="me"&gt;..&lt;/div&gt; $("#me").click(function() { alert("1"); }); $("#me").click(function() { alert("2"); }); $("#me").bindFirst('click', function() { alert("3"); }); $("#me").click(); // alerts - 3, then 1, then 2 </code></pre> <p><strong><em>However</em></strong>, since <code>.data('events')</code> is not part of their public API as far as I know, an update to jQuery could break your code if the underlying representation of attached events changes from an array to something else, for example.</p> <p><em>Disclaimer: Since anything is possible :), here's your solution, but I would still err on the side of refactoring your existing code, as just trying to remember the order in which these items were attached can soon get out of hand as you keep adding more and more of these ordered events.</em></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload