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