About Me

Curriculum Vitae

A brief list of my current skill set

Bloggybits

Automatically Cropping Images is Hard
Monday, 21st October 2013, 19:00

But maybe we can use face detection?

The Git Cheat Sheet
Friday, 6th September 2013, 11:30

for github, bitbucket, that kinda stuff

CoffeeScript and TypeScript are Stupid
Saturday, 17th August 2013, 11:21

Don't use them!

Changing the Order of the jQuery Event Queue
Wednesday, 3rd July 2013, 20:27

It's just a push to the left

How Do Spammers Get My Email Address?
Wednesday, 15th May 2013, 18:03

I think these days I have a pretty good idea

XSLT, node.js 0.10 and a Fun Two Days of Native Modules and Memory Leaks
Thursday, 25th April 2013, 17:14

documentation makes things less cryptic, so lets not write much of it

Fixing CentOS high cpu usage when running as a virtual machine under VirtualBox
Sunday, 21st April 2013, 20:28

innotek rocks! I mean Sun... I mean Oracle...

Repairing a dK'Tronics Keyboard and Scoping Out a ZX Spectrum 48k - Part One
Sunday, 17th March 2013, 23:51

What signals inside of it actually look like

Tabs vs Spaces and Why You Should Always Use Tabs
Monday, 4th March 2013, 19:51

Spaces are bad, just real bad

Why you should ban Amazon's Cloud IPs
Thursday, 27th December 2012, 14:50

And how to do it in nginx, Merry Christmas Amazon

Building Better jQuery DOM Inserts
Thursday, 20th December 2012, 15:18

Break it down baby

Projects and Sillyness

MAME Cabinet Diary

How I built my own arcade cabinet

Loading Screen Simulator

I don't miss the ZX Spectrum, I still use it!

The Little Guy Chat Room

It's a Pitfall inspired chat room

GPMad MP3

A fully featured MP3 player what I wrote

GP Space Invaders

My first little emulator

GP32 Development Page

Some info and links about this cute little handheld

Disney Nasties

Uncensored images, you must be 18 to view them

Minna's World

The cuttest fluffy puppy in the world

Diary of a Hamster

Learn about how hamsters think, first hand

Utilities

Time Calculator

A simple little online utility for working out how many hours to bill a client

A Few Links

Changing the Order of the jQuery Event Queue
Wednesday, 3rd July 2013, 20:27

So jQuery is great and everything, but sometimes you have a bunch of click events (or similar) bound to a DOM element and you want to change somehow the order they happen in. But how?

This is something I found myself needing to do last week, because I had a page with a large number of custom jQuery plugins bound to it, and I wanted to prevent all further jQuery click events on a button if certain conditions were met. Simple you might ask, event handlers are triggered in the order they were bound, so just bind it first and then call stopImmediatePropogation() inside the handler.

But this isn't always possible, binding the event first, especially if you are in an environment not of your own making, which includes javascript files you have little control over before the one you add has a chance to have it's fun.

After an awful lot of fruitless googling, I did find the odd hint on how to do it, so armed with the Chrome debugger (you know the one, that mad thing that gets all your breakpoints confused when you refresh a page and triggers them in the wrong places until it's loaded) I started poking around and spamming objects to the console.

Eventually, I managed to work it out, and it's actually really simple to move an event to the front of the queue. And by understanding how the process works you should be able to re-order the queue in other ways if you feel so inclined.

Exposing the jQuery Event Queue

The first thing we need to do is get hold of the events object for a given DOM element. The problem is it's not a public piece of data as far as jQuery is concerned, so we have to use the undocumented _data function to get at it. First a tiny bit of HTML:

<a id="mybutton">Click Me!</a>

And now a tiny bit of Javascript:

var eventList = $._data($("#mybutton")[0], "events");

Before you start asking, the array index [0] reference is needed because the data is referenced from the DOM object itself and not a jQuery object. You could rewrite the above as follows and it would work just the same (and maybe a bit faster):

var eventList = $._data(document.getElementById("mybutton"), "events");

This returns a simple object linked to our anchor DOM object which has no jQuery event handlers bound to it, so is empty! Note, I said empty as in { }, not null. However if it did have a few things bound then it would look something like this:

Object { keydown: Array[2], blur: Array[2], remove: Array[1], keypress: Array[1] }

Believe it or not, we are almost nearly there, each of those arrays contains a list of event handler objects. Now before you go just adding your own functions to the list, it's worth bearing in mind these are not arrays of functions, they are arrays of objects, each of which contains various jQuery specific properties so you really don't want to go adding them yourself. Especially if you want to maintain a level of compatibility with future jQuery versions.

If you expected a full tutorial on re-ordering the event queue I'm sorry to disappoint, I've got you this far and I'm only going to take you a tiny bit further because I can't think of anything more useful than the final bit I'm going to show you, so I'll just show you that and if it's not enough for your needs then you can work the rest out yourself.

Ensuring Your Event is First in the Queue

Now for the easy bit, say we have gotten the events object into our eventList variable as described above? How do we make sure the very next click event (as an example) we bind is always executed first?

Easy! You just remove it from the end of the array for that event before any more are bound, and put it at the beginning. Like this:

$("#mybutton").click(function(event) {
if ($(this).hasClass("disabled")) {
event.stopImmediatePropagation();
return false;
}
});

var eventList = $._data($("#mybutton")[0], "events");
eventList.click.unshift(eventList.click.pop());

Easy huh?

We bind our new click event first, and that gets added as the last entry to the click property of the events object. The click property is an array, so we just pop it off the end and unshift it onto the front.

Now we can disable our button by just adding the disabled class, which gives us a two for one deal since we need to change the style so it shows users it's disabled anyway.

There are lots of other uses and needs to insert something into the beginning of an event queue in jQuery, but if you've read this far then you already have that need so I won't bore you with them. :)

Comments

Add Your Own Comment