Custom Events in JavaScript

by kirupa   |   12 February 2015

Despite the large number of events JavaScript provides out of the box for a whole bunch of scenarios, there will be times when you want to fire your own events for your own particular needs:

I will fire my own event whenever I want to

There are many reasons for why you may want to do that. Events provide a nice level of decoupling between the thing that fires the event and the thing (or things) that listen for that event. In the event-driven world that we live in, your DOM elements don't have to be intimately familiar with the inner workings of your code. By relying on events, you have a great deal of flexibility in changing things around in your UI or in your code without breaking things and doing a lot of cleanup afterwards. That is what makes the built-in events so useful. That is what will make custom events you create (and fire) useful as well.

To take advantage of this usefulness, JavaScript provides you with just what you need. You have the appropriately named CustomEvent that does all sorts of awesome things, and in this short article, we'll take a detailed look at it.

Onwards!

Internet Explorer Warning

While Microsoft Edge supports everything you are about to see, Internet Explorer doesn't support the CustomEvent object being used as a constructor. Fear not. After reading this article, use the polyfill mentioned by the fine folks at MDN for support on (the ever-shrinking population of) older browsers.

Thanks to David in the comments below for pointing this out!

 

Using CustomEvent

As its name implies, the CustomEvent interface is what you will use to create your own custom event. The first thing is to create your custom event by calling the CustomEvent constructor:

var myEvent = new CustomEvent("myEventName");

The CustomEvent constructor takes a few arguments, but the only argument you absolutely need is the one that stands for the event name. In our case, our event is going to be creatively called myEventName. The CustomEvent object that wraps all of that is associated to the myEvent variable.

Why not use Object.create?

In the Deeper Look at Objects article, I mentioned that all the cool kids create new objects by using Object.create() as opposed to the more traditional new Blah() approach. That is true when the objects you create are instances of a source object you define, and you don't care about inheritance. For objects you create, you'll almost always have nothing to inherit from in the first place!

When creating objects based on built-in types with a lot of ancestors, the new approach allows you to easily create your new object while also inheriting from all of its ancestors. Our CustomEvent inherits from Event, so creating a new CustomEvent object ensures that my new object automatically inherits all the properties from Event as well.

With your event created, the next step is to actually fire the event. The way you fire an event programmatically is by using the dispatchEvent method:

var myEvent = new CustomEvent("myEventName");
document.body.dispatchEvent(myEvent);

You call dispatchEvent on the element that you want to act as your event target (aka the element that actually fires the event). In our case, that element is the body. At this point, you are done. You have your shiny, custom event and the code to actually trigger it. All you need to fully complete the circle is an addEventListener somewhere in your app that is listening for this event:

document.body.addEventListener("myEventName", doSomething, false);

Just make sure that your addEventListener code runs before you actually dispatch the event. Otherwise, you'll find that your event will fire before your event listener is even ready.

A Simple Example

In the previous section, you saw what was needed to create a custom event and fire it. To see it all working in a very trivial example, check out the following:

document.body.addEventListener("myEventName", doSomething, false);

function doSomething(e) {
	alert("Event is called: " + e.type);
}

var myEvent = new CustomEvent("myEventName");
document.body.dispatchEvent(myEvent);

If you happen to run this code, you'll see the alert statement inside the event handler gets called. That's because your myEventName was fired and the event listener reacted to it. Speaking of event handlers, before we move on further, there is something interesting inside it that I want to call out:

function doSomething(e) {
    alert("Event is called: " + e.type);
}

Notice that I am polling the event argument for the value of the type property. Despite us never having specified the type property as part of our CustomEvent, the type p property (along with a bunch of other event argument related properties) are available to your event handler. To reiterate what I mentioned in the note earlier, the reason is that CustomEvent inherits from Event. Even if you don't do anything extra, using CustomEvent will get you all the Event-related properties for free.

Specifying Custom Event Properties

While the built in Event properties provide you with a lot of useful information, you can also specify your own custom event properties for your custom event! This requires using the CustomEvent constructor's second argument and passing in a value for the detail property:

var myEvent = new CustomEvent("myEventName",
    {
        'detail': Math.round(Math.random() * 1000)
    });

In your event handler, I can access this detail property just like I would any other property associated with the Event object:

function doSomething(e) {
    alert("Event detail is: " + e.detail);
}

The thing to be aware of is that you don't have a recommended way of adding any more properties to the detail property. The unrecommended way would be to extend your CustomEvent object, but you do have a much easier way to provide more properties. Simply assign an object with the additional properties to the detail property:

var myEvent = new CustomEvent("myEventName",
    {
        'detail': {
            first: "Chalupa",
            last: "Batman",
            random: Math.round(Math.random() * 1000) 
        }
    });

You can access these properties by just dotting into the detail property instead:

function doSomething(e) {
    alert("Event detail is: " + e.detail.first);
}

Because you have an easy way to specify additional properties by relying on the detail object itself, you shouldn't extend the built-in Event or CustomEvent.

The DOM and Dispatching Events

In many languages, it is common to use events as a way of signaling changes between various internal components inside your app. These components may have no UI or even direct user-interaction associated with them. In the HTML world, things are a bit different. Out of the box, you can only dispatch events from DOM elements. You can't dispatch events from arbitrary Objects you may be working with.

The key to what I mentioned is the words "out of the box". This StackOverflow question describes how you can manually add universal event dispatching. Some 3rd party libraries can also help with this, so I'd suggest googling around for the latest library in case you need it.

Conclusion

For many people, studying how to decouple the visuals (aka DOM) from the internals of your code is a favorite hobby. The internets are filled with lots of text, funny sounding names, and code snippets on how to best accomplish this separation between what you see and what your code does. Using custom events to achieve that isn't the perfect solution, but it is very VERY close...depending on who you ask!!!

Getting Help

If you have questions, need some assistance on this topic, or just want to chat - post in the comments below or drop by our friendly forums (where you have a lot more formatting options) and post your question. There are a lot of knowledgeable and witty people who would be happy to help you out

Share

Did you enjoy reading this and found it useful? If so, please share it with your friends:

If you didn't like it, I always like to hear how I can do better next time. Please feel free to contact me directly via e-mail, facebook, or twitter.

Kirupa Chinnathambi
I like to talk a lot - A WHOLE LOT. When I'm not talking, I've been known to write the occasional English word. You can learn more about me by going here.

Add Your Comment (or post on the Forums)

blog comments powered by Disqus

Awesome and high-performance web hosting!
BACK TO TOP
new books - yay!!!