Is there a way to attach a jQuery event handler such that the handler is triggered before any previously-attached event handlers? I came across this article, but the code d
@patrick: I've been trying to solve the same problem and this solution does exactly what I need. One minor problem is that your plug-in doesn't handle namespacing for the new event. This minor tweak should take care of it:
Change:
var evt = $.data(this, 'events')[type[len]];
to:
var evt = $.data(this, 'events')[type[len].replace(/\..+$/, '')];
I create a very simple function to put my click event handler at first position, and all existing click handlers will only be triggered manually.
$.fn.bindClickFirst = function (eventHandler) {
var events = $._data($next[0], "events");
var clickEvtHandlers = [];
events.click.forEach(function (evt) {
clickEvtHandlers.push(evt.handler);
});
$next.off("click");
$next.on("click", function () {
var evtArg = event;
eventHandler(evtArg, function () {
clickEvtHandlers.forEach(function (evt) {
evt(evtArg);
});
});
})
}
And to use the function:
$btn.bindClickFirst(function (evt, next) {
setTimeout(function () {
console.log("bbb");
next();
}, 200)
})
As answered here https://stackoverflow.com/a/35472362/1815779, you can do like this:
<span onclick="yourEventHandler(event)">Button</span>
Warning: this is not the recommended way to bind events, other developers may murder you for this.
There is a rather nice plugin called jQuery.bind-first that provides analogues of the native on
, bind
, delegate
and live
methods which push an event to the top of the registration queue. It also takes account of differences in event registration between 1.7 and earlier versions. Here's how to use it:
$('button')
.on ('click', function() { /* Runs second */ })
.onFirst('click', function() { /* Runs first */ });
As with most of these answers, the big disadvantage is that it relies on jQuery's internal event registration logic and could easily break if it changes—like it did in version 1.7! It might be better for the longevity of your project to find a solution that doesn't involve hijacking jQuery internals.
In my particular case, I was trying to get two plugins to play nice. I handled it using custom events as described in the documentation for the trigger method. You may be able to adapt a similar approach to your own circumstances. Here's an example to get you started:
$('button')
.on('click', function() {
// Declare and trigger a "before-click" event.
$(this).trigger('before-click');
// Subsequent code run after the "before-click" events.
})
.on('before-click', function() {
// Run before the main body of the click event.
});
And, in case you need to, here's how to set properties on the event object passed to the handler function and access the result of the last before-click
event to execute:
// Add the click event's pageX and pageY to the before-click event properties.
var beforeClickEvent = $.Event('before-click', { pageX: e.pageX, pageY: e.pageY });
$(this).trigger(beforeClickEvent);
// beforeClickEvent.result holds the return value of the last before-click event.
if (beforeClickEvent.result === 'no-click') return;
what about this? bind the event and than do this:
handlers.unshift( handlers.pop() );
My best attempt.
I had code that was structured as follows:
var $body = jQuery('body');
$body.on({
'click': function(event){
}
});
To then ensure that the callback was the first one called, I used this function:
/**
* promoteLastEvent
*
* @access public
* @param jQuery $element
* @param String eventName
* @return void
*/
function promoteLastEvent($element, eventName) {
var events = jQuery._data($element.get(0), 'events'),
eventNameEvents = events[eventName],
lastEvent = eventNameEvents.pop();
eventNameEvents.splice(1, 0, lastEvent);
};
This is called as follows:
promoteLastEvent($body, 'click');
It works quite well for me, given my limited use of $.fn.on
.