WinJS Event Aggregators And Observable/Evented Objects


In a previous post, I showed a very brief intro to using an application level event aggregator in WinJS. At the end of that post, I hinted at an option I was looking in to for creating localized event aggregators – basically, objects that can be observed. It turns out the path I was heading down was right, and it’s super simple to implement an evented object in WinJS.

A Brief Detour: WinJS “Class”

Before I show you how to create an evented object in WinJS, you need to know how to create a “class” in WinJS. This is done by passing a constructor function and/or a list of methods as an object literal in to a WinJS.Class.define API:

There are two other methods on the WinJS.Class object, which are also useful but not important to this blog post.

Personally, I think it’s very unfortunate that they chose to use the word “class” for this. It will be misleading and cause problems for developers that come from other languages, because people will expect the result to be a class. And while JavaScript functions can be used to create new object instances, thus behaving like a class a little, they are not classes. (For more of my thoughts, read this post on class-y frameworks)

But moving on…

Making An Object Evented

Now that we know how to build a “class” in WinJS, we can very easily add an implementation of the observer pattern to the object, allowing it to trigger events that other objects can listen to.

Here’s how you do that, using WinJS.Utilities.eventMixin:

Yes, it’s that easy. One line of code, and you’re done. This object is now capable of triggering events and having those events listened to, which gives us everything we need to either create a dedicated event aggregator or just have our objects trigger events to facilitate workflow or other event-driven features of our app.

Triggering, Handling, and Removing Event Handlers

Triggering and handling events in an eventMixin object is a little different than in the WinJS.Application, but should be familiar to anyone that has done DOM events, jQuery events or Backbone events.

To trigger an event, call the “dispatchEvent” method and pass the name of the event as the first parameter, with the event arguments as the second parameter.

To handle an event triggered by another object, call the “addEventListener” method and tell it what event you want to listen to, then provide a callback function that receives the event arguments.

Lastly, event handlers can be removed via a call to the “removeEventListener” method.

(You may have noticed the “useCapture” parameter in the documentation for both the addEventListener and removeEventListener methods. I have no idea what this does.)

Managing Memory

One last tip with event aggregators and evented objects: You are responsible for memory management with observable / evented objects. While this may not play out the same way that C++ forces you to allocate / deallocate memory, it’s still very true. If you allow a function to be triggered by an event, and that function is a method, then the object that holds a reference to the method runs the risk of becoming a memory leak.

Fortunately the solution to this is easy: remove your event bindings when you’re done with them.

I’ve written about this a lot in context of Backbone and in JavaScript in general. The same rules apply to WinJS as well. In fact, I’ve had this notion in the back of my mind already, that I need to create an EventBinder object for WinJS the same way I did for Backbone.Marionette, as a core part of my own application’s memory management. We’ll see if I ever get a chance to do this, but I think it is something that needs to be done.

Just remember: it’s your responsibility as a developer to understand that this is the nature of the observer pattern and references. And just because you’re running a managed / garbage collected language, doesn’t mean you can’t create memory leaks and zombies.

A Quick Note On Pub-Sub / Event Aggregators In WinJS/WinRT