Skip to content
krasimir edited this page Feb 13, 2011 · 7 revisions

As a huge fan of the flash platform, I've always liked to work with events. The events system in ActionScript3 is really helpful when we are building a big application with many modules and we want to keep them independent. JavaScript doesn't have native support of events, but we can still use them.

1. Events basics

The events are used in the communication between modules of the application. Let's imagine that we have a basic web blog page like this one:

EventBus

And let's say that if you click on contacts we will update the content's area and we will replace the banners' area with our latest articles. Normally we can use something like:

menu.contacts.click = function() {
    contentArea.update("contacts data");
    bannersArea.update("latest articles data");
}

That's fine and probably will work for us, but what if you want to add something else. We will have to add additional functions to the code above. Now imagine that we are using classes and we have a complex hierarchy of objects. It is not so easy to have access to these objects in every function. Something also very important is that we can't transfer these classes to some other project, because they are tightly connected to each other. By using events we are solving all these problems. The idea is that we have dispatchers (classes that fire events) and listeners (classes that listen for events).

EventBus

So, in the situation above our menu object dispatches an event the contacts button is clicked. The content's area and the banners' area are waiting for this event and they will update themselves when they catch this event. In other words:

menu.contacts.dispatch("the contacts button is clicked");
...
...
...
contentArea.addEventListener("the contacts button is clicked", function() {
    // update code here
});
bannersArea.addEventListener("the contacts button is clicked", function() {
    // update code here
});

As you can see, our objects are completely independent. The menu object doesn't care what will happen when the contacts button is clicked. It just informs the other modules for that and this is its job. Also we can easily transfer the menu class to some other project. The only thing that we have to know is which events will be dispatched.

Managing events (the EventBus class)

Unfortunately JavaScript doesn't have native methods like dispatch and addEventListener. We have to create them manually. Inspired by RobotLegs (AS3 micro-architecture) I created a class called EventBus. It has the following methods: a) addEventListener - adding a listener b) removeEventListener - removing a listener c) dispatch - dispatching event d) getEvents - for debugging purpose, it just prints out the added listeners

Simple dispatch/listen

We are adding myFunction method as a listener for the my_function_event and after that simply dispatching the event.

function myFunction(event) {
    alert("myFunction type=" + event.type);
}
EventBus.addEventListener("my_function_event", myFunction);
EventBus.dispatch("my_function_event");

Passing the dispatcher

var TestClass1 = function() {
    this.className = "TestClass1";
    this.callback = function(event) {
        alert(this.className + " = type:" + event.type + " / dispatcher:" + event.target.className);
    }
};
var TestClass2 = function() {
    this.className = "TestClass2";
    this.dispatchOurEvent = function() {
        EventBus.dispatch("callback_event", this);
    }
};
var t1 = new TestClass1();
var t2 = new TestClass2();
EventBus.addEventListener("callback_event", t1.callback, t1);
t2.dispatchOurEvent();

As you can see we have two classes - TestClass1 and TestClass2. Each one of them has a property called className (if you have troubles understanding the classes in javascript please check this article). Of course the property is different for the two classes. What we did above is to add a listener for the event callback_event and then dispatch it. When we use classes it is good to add the scope of our listener's function. In our case the function is callback and the scope is t1. The actual version of the addEventListener function is:

function addEventListener(type, callback, scope) { ... }

and for the dispatch method:

function dispatch(type, target) { ... }

If we don't pass the scope we will not have an access to className property. If you test the example above you will see that the result is:

TestClass1 = type:callback_event / dispatcher:TestClass2

Something else that is very important to know is that every listener's function receives an object, which has two properties: a) type - the name of the dispatched event b) target - the dispatcher (if is passed)

Passing custom parameters to the listener's function

var TestClass1 = function() {
    this.className = "TestClass1";
    this.doSomething = function(event, param1, param2) {
        alert(this.className + ".doSomething");
        alert("type=" + event.type);
        alert("params=" + param1 + param2);
        alert("coming from=" + event.target.className);
    }
};
var TestClass2 = function() {
    this.className = "TestClass2";
    this.ready = function() {
        EventBus.dispatch("custom_event", this, "javascript events", " are really useful");
    }
};
 
var t1 = new TestClass1();
var t2 = new TestClass2();
 
EventBus.addEventListener("custom_event", t1.doSomething, t1);
t2.ready();

It is possible to pass as many parameters as you want when you are dispatching an event:

EventBus.dispatch("custom_event", this, "javascript events", " are really useful");

I passed two strings javascript events and are really useful. The only thing you should consider is that your parameters are coming after the event object in the listener's function.