with Imagination: by Dustin Diaz

./with Imagination

A JavaScript, CSS, XHTML web log focusing on usability and accessibility by Dustin Diaz

Publishing Custom Events in JavaScript

Sunday, May 28th, 2006

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!

38 Responses to “Publishing Custom Events in JavaScript”

  1. Andrew Dupont

    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.

  2. Andrew Dupont

    [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, bar will 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 that dojo.event.connect does to make this possible.

  3. Dustin Diaz

    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.

  4. Sam

    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?

  5. Nathan Smith

    Hey Dustin, nice writeup, and an even better live example. I especially like the line: “This is not Ajax.”

  6. kentaromiura

    @(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 ;)

  7. Ryan Irelan » Publishing Custom Events in JavaScript

    […] Publishing Custom Events in JavaScript - Bookmarked for later reference. […]

  8. Hermann Klinke

    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…

  9. Dustin Diaz

    @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.

  10. Peter Pistorius

    Wow! That example looks great! YUI rawcks!

  11. Hermann Klinke

    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)

  12. Hermann Klinke

    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”);

  13. Dustin Diaz

    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.

  14. Darren Hoyt

    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.

  15. Hermann Klinke

    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.

  16. Dustin Diaz

    @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.

  17. Hermann Klinke

    I just checked out your animated menu page. The animation is beautiful and you’ve got great “Javascript Homies” there. Thanks!

  18. Jared

    > 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.

  19. links for 2006-06-03 at /dev/caffeine

    […] Publishing Custom Events in JavaScript define your own events in javascript. tres cool. (tags: javascript events tutorial yui yahoo) […]

  20. Timothy Rosenberg

    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!

  21. kim steinhaug

    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

  22. Seth Dillingham

    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.

  23. Sam’s random musings » Creating Custom Events with JavaScript: Decoupling

    […] 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.) […]

  24. Chris Ovenden

    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

  25. Willie Lassiter

    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.

  26. Greg Bugaj

    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.

  27. Alex

    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.

  28. nicolash

    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).

  29. Ravi Gidwani

    Thanks Dustin. Great articel. Probably we can create a JWT (Javascript Windowing Toolkit) using this approach.

  30. sudhir

    Check out dojo event publish and subscribe.

    http://www.jyog.com

  31. Levi Hackwith

    Hey Dustin!,

    Great article. I was wondering, could you cover how to pull off custom events without using a third-party library like YUI?

  32. Dennis Wong

    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.

  33. Ruben

    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?

  34. perfection kills » Blog Archive » Detect idle state with custom events

    […] 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). […]

  35. CMG

    is it possible to track which button was clicked, when window.print() method was fired.

  36. Geek Daily » Blog Archive » JavaScript defining and using custom events

    […] Dusint Diaz explains custom events extemely well in his post about JavaScript custom events. […]

  37. Belial9

    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!

  38. artwise

    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

Leave a Reply

Phone Number:

If you're about to post code in your comment, please wrap your code with the tag-combo <pre><code>. Also please escape your html entities - otherwise they will be stripped out. I recommend using postable.

Get "JavaScript Design Patterns"

"As a web developer, you'll already know that JavaScript™ is a powerful language, allowing you to add an impressive array of dynamic functionality to otherwise static web sites. But there is more power waiting to be unlocked--JavaScript is capable of full object-oriented capabilities, and by applying OOP principles, best practices, and design patterns to your code, you can make it more powerful, more efficient, and easier to work with alone or as part of a team."

Buy JS Design Patterns from Amazon.com Buy JS Design Patterns from Apress

Flickr

Submit a Prototype

All content copyright © 2003 - 2007 under the Creative Commons License. Wanna know something? Just ask.

About | Archives | Blog Search

[x] close

Loading...

Submit a prototype

By checking this prototype I agree that I am not submitting false credentials, pornography, or a hate crime website. I also understand that by submitting my entry I may or may not be accepted, and if accepted, my entry may be taken down at any given time if I violate these terms.