Publishing Custom Events in JavaScript
By now anyone who spent at least one week of learning JavaScript in their life, they know about events. Although they may not exactly know all of them or how to make them do something upon them firing, we should all indeed know of the select few like click, dblclick, mouseover, mouseout, focus, blur, and submit to name a couple. These are all events known to us that we can define as interesting moments
available to us in the DOM that we can listen for. Got it? Wonderful…
So what’s a custom event?
A custom event(s) is/(are) the interesting moments
that you get to define in your web application. Still confused? Yea. I think I was too. If this is a new concept to you, don’t feel left out. Keep in mind this isn’t a built-in JavaScript function, but rather a proof of concept that allows for better event abstraction.
Brief overview of normal DOM events
When we describe normal events to our peers as a series of interactions, we generally say something like For this tab menu, I want to swap the colors, then change the message on ‘click’ of the tab.
. Or if that sounds too awkward. We’ll say When the user ‘clicks’ on the tab, I want to swap the colors and change the message.
I can see it swindling in your brain already. Sure enough, the first thing that would normally come to a scripters mind is…. I’ll assign a ‘click’ event to the tab that fires a function which will swap the colors, then change the message
. Fair enough. That totally works and that’s the way most people do it. As a matter of fact, just about all the code on this site follows that model as well… nevermind the fact that it’s about a year old now since I last touched it.
Examples of custom events
A custom event in this same model can be something you, yes you, get to make up. Looking at our tab/click/swapColor/changeMessage illustration, we can easily turn this into an event called onTabChange. In return, anytime our tab menu changes state, we can notify our listeners/subscribers that this event occured; then do whatever the heck we want on the fly.
A Parallel illustration
Think about the normal event model. There are event handlers, and there are event listeners. The benefits of a listener (IMO) far outweigh those of a handler. Mainly because a handler is something that ‘handles’ that event when triggered, and a listener can be one of many that just sits around and waits for the event to fire. If that doesn’t make any sense. Just know that there can only be one event handler, but several listeners. A handler is more likely to get overridden.
Likewise, custom event subscribers follow the same model as listeners. Take special note that just a ‘custom event’ all by itself is not does not need to follow the subscriber/listener model; that in and of itself is just the thing you get to define. It can be a handler or a listener event.
So, how do I make a custom event?
First of all, you need to decide which parts of your web site are going to have these custom events, and if they’re going to be useful to publish. Although you may be the only consumer of these events (meaning, nobody else is working on the project but you), it’s still probably a good idea to abstract your events.
Whoa. Hold up. Can I get some more examples?
Sure. Here’s a random compiled list that could possibly qualify as custom events:
- onMenuCollapse
- onMenuOpen
- onColorChange
- onDrag (drag and drop)
- onDragComplete
- onTween (animation)
- onColorPick
- onSlide
- onUserWaitedTooLong
- onRotate (tetris)
- onMoveLeft (tetris)
- onMailCompose
- onHilight
- onEdit
- onSave
- onUpdating
- onComplete
So how do I make these happen?
Glad you asked. After you’ve decided what would be useful to have as a custom event, you can use the YUI event utility to define your events, subscribe to them, then fire them at will (what? You weren’t expecting me to talk about Yahoo! again?).
First off, the code is dirt simple. Assuming you’ve planted the correct files into your web document like follows:
adding YUI event util
<head>
...
<script type='text/javascript' src='js/yahoo.js'></script>
<script type='text/javascript' src='js/event.js'></script>
...
</head>
From this point on, it’s best to assume the following two rules for making custom events.
Rule 1) As the Producer/Publisher of the events, we decide what qualifies as the event and define it. Furthermore we are also the ones that get to fire the event.
Rule 2) As the Consumer of these events, we get to subscribe and fire whatever functions we want when those events get fired from our publisher.
So, as the publisher we can now define our custom event:
defining your custom event
var onMenuCollapse = new YAHOO.util.CustomEvent('menu collapse');
And now fire it at some point in our library.
firing your custom event
/* paZow Sucka */
onMenuCollapse.fire();
In a real-world situation, if you’re part of a team of developers, it would be best to notify the fact that you’ve published this event. Thus noting to the others that they can listen for this event at whatever moment they want if they need to update the document at a later time. If these developers aren’t around…. then document the hell out of your code noting that You can listen for this event!
However, that’s unlikely. Most folks coming in at a later time aren’t going to know what a custom event is…. so they can call you and you can act like the chosen smart one ;)
Subscribing to the custom event
Simple enough. You can listen for it like this:
subscribing to an event
onMenuCollapse.subscribe(swapColors);
.
.
.
function swapColors() {
// do stuff here
}
Wonderful, can I see something?
Sure. Like most practical developers, you often need to see something. One pet peeve of mine is reading JavaScript tutorials that just talk about the language itself and philosophies of code rather than showing a real use of it all. It would be the equivalent of trying to explain OO JavaScript while talking about bears, balloons, boats, and other forms of animals and fairies.
Anyway, here is the most basic (dull) example for you to get an idea of how custom events work with a simple event called ‘myEvent’. You can view that here. You might even come back to that example because it shows you what you can do with certain perameters and arguments etc…
Here is an illustration of Drag and Drop custom events being extended to have subscribers
(which it normally doesn’t have (FYI - feature request)). You’ll notice that the instance of the box being dragged has an onDragging event and an onComplete event that you can subscribe to. Take special note that the onComplete event is being fired twice to change the colors of each of the boxes.
Of course, here is another example of an Animation Menu with Custom Events which illustrates the use of onMenuOpen and onMenuCollapse.
In all cases I advise you to take a peek at the code to get a better understanding of what’s actually going on. Enjoy!













May 28th, 2006 at 11:54 pm
Well done. In my own writings I think I’ll have to start referring to you as “Dustin Diaz, YUI Pimp.” Everyone needs an epithet.
If you don’t care about abstracting away the difference between browser events and custom events, this sort of thing can be done with almost no code at all. You’d have a hash with event names as strings (”onMenuCollapse” and such) and arrays as values; each array would hold the functions that have been “hooked onto” the event.
May 28th, 2006 at 11:56 pm
[Whoops… somehow the rest of my comment got cut off.]
Your “register” method would push the function into that event’s array, and the “fire” method would simply find the event’s entry in the hash and fire each of its listener functions in turn.
Dojo’s event system, though not my cup of tea, is admittedly really cool when it comes to event-driven applications, because you can make connections implicit rather than explicit. So you could say “make sure foo() always fires right after bar()” — and then when you invoke
foo,barwill be called automatically, so you don’t have to have a “fire” method. I am simultaneously in awe of and deeply creeped out by the amount of voodoo thatdojo.event.connectdoes to make this possible.May 29th, 2006 at 12:08 am
Aww. YUI Pimp. That’s…. fine with me.
Yea, this was one thing that I think Dojo does very well, but it’s just very buried under it all and under-documented. I wish Alex would get his butt in gear and get some solid remarks on how I can use it (wink wink Alex ;)). Indeed there is a blog post about it that I read, but I still felt overwelmed and wasn’t sure what dependencies I needed etc…
The YUI Custom Event util was Adam’s first pass and trying to abstract these events in a way that seemed logical at the time. After all, it works perfectly in companionship with the Animation util, eg.
animInstance.onTween(myMethod).Beyond it all though, I still think Adam has something else up his sleeve.
May 29th, 2006 at 12:30 am
I’m really interested in learning about Custom Events but I don’t use the YUI library so I was a bit disapoint to hit the implementation and see it used. How would you create Custom Events without use of external libraries?
May 29th, 2006 at 1:01 am
Hey Dustin, nice writeup, and an even better live example. I especially like the line: “This is not Ajax.”
May 29th, 2006 at 2:28 am
@(Sam):
you could do in a lot of manner:
var obj={}
//define a C-E
obj.onWhenISaid = function Goofy(){
alert(”just when i said”);
}
..
later in the code
..
//fire the C-E
obj.onWhenISaid();
or
var customEvents = [];
//define a C-E
customEvents[”onWhenISaid2″]=function (){
alert(”just when i said ;)”);
}
..
later in the code
..
//fire the C-E
customEvents[”onWhenISaid2″]();
or let’s your imagination do it for you ;)
May 29th, 2006 at 7:02 am
[…] Publishing Custom Events in JavaScript - Bookmarked for later reference. […]
May 29th, 2006 at 7:16 am
Alright, fuck it. Dustin, you should fix you comment system, because it makes posting code impossible, because the comment is cut off all the time…
May 29th, 2006 at 11:01 am
@Hermann, I noticed the other two of your comments in the moderation queue. They happnened to get cut off because you did the classic loop…
for ( var i=0; i <len; ++i ) {// etc...}Note the ‘<’ less than sign. That’s like opening up an html tag, but then never closing it ;) FYI, next time just escape your html. You’ll find out that I’m actually very forgiving on what you can post, and I interested in seeing the code you were in the middle of writing. :(
@Sam, don’t be disappointed. Our event util is a little less than 2k. That’s really the size of a toothpick when you compare that to anything else.
@kentaromiura, that example just extends objects with functions attached. It doesn’t exactly follow the subscriber/listener model. The focus here is on the consumer, and not the publisher exactly firing the events. It’s easy to fire events whenever you want. The CustomEvent util allows you to wait and listen for those events to fire as I believe the Dojo event system does as well.
@Nathan, yep. This is not Ajax :p - but you know eventually someone is going to tag it with that anyway.
May 29th, 2006 at 2:13 pm
Wow! That example looks great! YUI rawcks!
May 29th, 2006 at 3:26 pm
Alright, thanks for the info Dustin. So here I try again (escaped the code in CDATA tags):
Here would be my implementation if you don’t want to use YUI:
Dojo’s event system implementation isn’t that cracy either. I have not looked at the code, it would look something like that (again: I have not tested the code)
May 29th, 2006 at 3:29 pm
Ok, so CDATA does not work either (for the same reason ;-)). I’ll try escaping the characters individually:
Here would be my implementation if you don’t want to use YUI:
function Event()
{
this.eventHandlers = new Array();
}
Event.prototype.addHandler = function(eventHandler)
{
this.eventHandlers.push(eventHandler);
}
Event.prototype.raise = function(args)
{
for(var i = 0; i < this.eventHandlers.length; i++)
{
this.eventHandlers[i](args);
}
}
function kickAssHandler(args)
{
alert(”event kickAss raised with argument ” + args);
}
//create event
onKickAss = new Event();
//add handler
onKickAss.addHandler(kickAssHandler);
//raise event
onKickAss.raise(”wohoo”);
Dojo’s event system implementation isn’t that cracy either. I have not looked at the code, it would look something like that:
var Event = new Object();
Event.connect = function(object, nameOfFunctionToCall, functionToCallAlso)
{
var functionToCall = object[nameOfFunctionToCall];
object[nameOfFunctionToCall] = function()
{
var self = arguments.callee;
for(var i = 0; i < self.eventHandlers.length; i++)
{
self.eventHandlers[i].apply(null, arguments);
}
}
object[nameOfFunctionToCall].name = nameOfFunctionToCall;
object[nameOfFunctionToCall].eventHandlers = new Array();
object[nameOfFunctionToCall].eventHandlers.push(functionToCall);
object[nameOfFunctionToCall].eventHandlers.push(functionToCallAlso);
}
//how to use:
function callAlso(args)
{
alert(”callAlso function called with argument ” + args);
}
var object = new Object();
object.callFirst = function(args)
{
alert(”callFirst function called with argument ” + args);
}
Event.connect(object, “callFirst”, callAlso);
//call both functions
object.callFirst(”wohoo”);
May 29th, 2006 at 4:05 pm
Hermann, very cool. FYI, I just like to type out all the code and then paste it on Postable, then come back and paste the results here. In fact I even do that when I’m writing entries.
Now finally looking at your code, that’s very similar and not far off what what YUI actually achieves. You can see that here. I’m not really sure if you’re trying to convince me to use Dojo, or if something I said was incorrect. YUI lays it out dirt simple.
var onFoo = new YAHOO.util.CustomEvent('onFoo');Somewhere else…
onFoo.fire();And to subscribe:
onFoo.subscribe(doSomething);onFoo.subscribe(doSomethingElse);But as I mentioned near the end, you might even see some changes beyond that thinking from Adam to make this even easier.
May 30th, 2006 at 12:04 pm
Great stuff, Dustin. One usability issue: on this page in IE, the parent nav elements (ex: “Javascript Homies”) don’t change colors on hover, nor is there a pointer “hand” to indicate they perform any function. Could be confusing for new users.
May 30th, 2006 at 1:19 pm
Thanks for the tip, I bookmarked Postable. No, I was not trying to convince you to use Dojo (I have not used it myself) and you did not say anything incorrect. I just wanted to post some code for sam and show that the implementation of dojo’s event system is probably not that cracy either. It just shows how powerful javascript is.
May 30th, 2006 at 1:21 pm
@Darren, the example doesn’t exist to show off user experience concepts. It was more or less an illustration of code. The real stuff is under the hood (view source). The stuff you mentioned can simply be cleaned up with css. This article is ‘not’ about that.
May 30th, 2006 at 2:14 pm
I just checked out your animated menu page. The animation is beautiful and you’ve got great “Javascript Homies” there. Thanks!
June 2nd, 2006 at 3:24 am
> Aww. YUI Pimp. That’s…. fine with me.
… or YUI Whore
Though I love the ultramagnetic mcs and Kool Keith … (no gangster rap) I dont like the misuse of words. Not even to make a stupid metaphor (ironic).
Dustin: you are a YUI evangelist! You see in one of his Ipod transmissions you have this celestial intro with a high pitched Dustin on a breakfast of Helium. The man is an evangelist.
June 2nd, 2006 at 5:30 pm
[…] Publishing Custom Events in JavaScript define your own events in javascript. tres cool. (tags: javascript events tutorial yui yahoo) […]
June 12th, 2006 at 8:27 pm
Hello,
Great tutorial Dustin. I hope you don’t mind that I ganked it for my site. The only problem I’m having is that instead of simple links as list items I’d like to have the flickr badge, a newsvine feed, del.icio.us linkroll and technorati blogroll. All of these use some sort of embedded javascript. Unfortunately, the sliding windows code can’t account for the necessary space those feeds need and the result is not very desirable. You can see my implementation of the code at timothyrosenberg.com/test.asp. If you click on linkroll you’ll see what I mean. Also, for some reason the blogroll tab is stuck open as well. Let me know what you’re thoughts are on how to fix this. I’m a total noob in javascript so be gentile. Thanks!
June 22nd, 2006 at 4:27 pm
interesting read dustin. kicking back with a beer on the psp here so typing is rather timeconsuming. looks like i need to spend some more time on the listeners, obviously something one needs to master in a modern app. cheers comrade
July 7th, 2006 at 1:14 pm
There’s another way to do custom events, also, that unbinds your objects better than most of the other approaches. At least, that was my intent.
I wrote an essay on the topic. (Hope you don’t mind the link.) Also, my sample code uses prototype.js, but the concept itself is what really matters.
July 11th, 2006 at 4:28 pm
[…] I’ve been playing around with this a little bit over the last few days and I have to say that it is cool, beyond cool it is more of a duh… of course this is how things should work. It’s really clever and works well in my limited world (I am fortunate to work mostly on intranet projects that have a very limited scope when it comes to supporting browsers. My guess is that we will see this article or others like it gaining some real traction (also see: http://www.dustindiaz.com/custom-events/ for another take from the Dojo side of the road.) […]
October 4th, 2006 at 7:39 am
Hi
I want to be able to read your article about custom js events, but I haven’t got past the weird CSS ‘feature’ which makes your page unreadable in every standards browser I’ve tried. I’ve had to fire up IE7 to write this comment. In Firefox 2.0, Flock and Opera the text is overbright and blurry and the chrome is even blurrier. Amusing in a quiet way, as Eyore might say, but not actually helpful. (And, as someone else pointed out, the ‘layout change’ buttons don’t work in FF. They do work in IE7 but make your comments unreadable.) Back to the drawing board, mate
Chris
October 20th, 2006 at 5:50 am
Have you tried the “Drag and Drop custom events” example with IE7s Page Zoom. It works better than most drag and drop examples I’ve seen. In that in IE7 when you zoom out to say 70% and drag the large square, it tracks the mouse fairly well. This is true even if you release the mouse and perform a second drag operation in the zoomed-out state.
But there does seem to be one problem associated with scrollbars added during a zoom-in. A simple example would be, zooming in to 130%, scrolling the screen all the way to the far right, and then trying to drag the square. The mouse cursor will change when you hover over the square, but you won’t be able to drag it.
I’m impressed that the Yahoo JS library works as well as it does with IE7 Page Mode. A lot of Web 2.0 apps are breaking on zoom-in: Meebo and Google Calendar for example.
December 13th, 2006 at 3:06 pm
Hi,
One thing to note about the subscribing function (listener) is that it should accept 3 arguments (min 2 if we don’t care for scope) in following format.
<pre><code>
function doMe(type, args, self) {
trace(type);
trace(args);
trace(self);
}
</code></pre>
while many people might be trying to use
<pre><code>
function doMe(args) {
trace(args)
}
</code></pre>
this will print the name of the customEvent in this case ‘onStateChange’ while some might expect arguments object.
If we don’t want to use parameters we can do this
<pre><code>
function doMe() {
trace(arguments)
}
</code></pre>
and we would get ["onStateChange",[[object Object]],[Window]].
This is rather elementary stuff but it is important to understanding how functions are exectued and what parameters are passed back by YUI. Damn my english does suck.
January 12th, 2007 at 7:11 am
Very useful article Dustin. The best part is that it’s not only theory and code. You have live examples which help a lot in understanding custom events.
January 18th, 2007 at 1:56 pm
hey dustin,
– css problem on your site (black font on black background)–
if i change the css via the style-switcher to get white bg in the main column (contrast2/Layout 5)- your own comments are black font on black bg. So i see a black area with some green spots (links).
April 19th, 2007 at 12:17 pm
Thanks Dustin. Great articel. Probably we can create a JWT (Javascript Windowing Toolkit) using this approach.
April 24th, 2007 at 1:59 am
Check out dojo event publish and subscribe.
http://www.jyog.com
May 1st, 2007 at 6:47 am
Hey Dustin!,
Great article. I was wondering, could you cover how to pull off custom events without using a third-party library like YUI?
July 3rd, 2007 at 7:22 pm
The article itself is good, compact, and easy to understand. But I think you should change the title to “Publishing Custom Events in Javascript with YUI”. In fact, I was expecting something in pure Javascript rather than using a 3rd-party library.
August 1st, 2007 at 12:27 am
Hello Dean, I has sometimes a question, namely I have a German homepage over Java Script and might I translate your rules and publish this on my homepage if I there but a link of you Page?
October 17th, 2007 at 10:21 am
[…] Before diving into all the dirty details, I’d like to mention that Andrew’s code encaplsulates “onIdle” logic into a one single function - this is where we would have to stop our requests/calculations. Such approach is absolutely fine but to decouple things a little we could abstract them into custom events. This will allow us to subscribe anyone to independently observe idle/active state of the user and act accordingly. There are quite few very, good, explanations of custom events, just in case you’re not sure what they are, as well as prototype, based, extensions. Prototype natively supports custom events since version 1.6 (which is not yet officially released). The implementation still varies (i.e. there were some drastic changes in one of the last revisions) but overall works flawlessly. In the following example I am going to use a new way of defining events - prefixing them with pseudo namespace (which I think is more descriptive). […]
March 9th, 2008 at 11:13 pm
is it possible to track which button was clicked, when window.print() method was fired.
April 2nd, 2008 at 8:11 am
[…] Dusint Diaz explains custom events extemely well in his post about JavaScript custom events. […]
May 18th, 2008 at 2:41 am
Hail you guys! collectively within this page, you have all managed to contribute so much in the ways of creating events! Thankyou Dustin, for initiating this, and to everyone else also for introducing the concept of using dojo. I shall now experiment with manipulating both varieties, and see which one feels more comfortable! (oftentimes, the answer is BOTH are the best, but dependant on the situation at the time!) So please remember, we’re not here to brawl about who wins, merely to observe the different techniques, and each of us aquire something new and fantastic to play and experiment with! (thus enriching our evergrowing array of neat little tricks!) ;) A Big WELL DONE To everyone who has participated!
June 2nd, 2008 at 10:15 am
Hey Dustin, great example, keep up good work!
One question:
If I want to have “really” custom event in javascript objects - can I do it?
var obj1 = {”property1″:true, “function1″:function(){},etc};
Now I need an event to fire whenever obj1.property1 changes its value (whether any code handles it is a different matter!):
obj1.property1 = false;
thanks