If you’re already using jQuery and you need an EventEmitter you may as well use jQuery’s event system instead of building your own. Here’s something I used in a recent project:
EDIT: made it simpler. (Now mixin: jQuery.eventEmitter
instead of jQuery.EventEmitter.prototype
.)
(function(jQuery) { jQuery.eventEmitter = { _JQInit: function() { this._JQ = jQuery(this); }, emit: function(evt, data) { !this._JQ && this._JQInit(); this._JQ.trigger(evt, data); }, once: function(evt, handler) { !this._JQ && this._JQInit(); this._JQ.one(evt, handler); }, on: function(evt, handler) { !this._JQ && this._JQInit(); this._JQ.bind(evt, handler); }, off: function(evt, handler) { !this._JQ && this._JQInit(); this._JQ.unbind(evt, handler); } }; }(jQuery)); |
It’s a mixin, and you can use it like so:
function App() { // do stuff } jQuery.extend(App.prototype, jQuery.eventEmitter); var myApp = new App(); // myApp supports events! myApp.on('someEvent', function() { alert('someEvent!'); }); myApp.emit('someEvent'); // 'someEvent' alerted |
Feel free to change the property/method names. The stuff prefixed with _JQ
should not be accessed publicly and should avoid conflicts with your objects. I guess you could use jQuery’s expando to hide them better. Or, alternatively, if performance is less of a concern, you can re-construct the jQuery object on each method-call instead of saving it.
When destroying your object be sure to call jQuery.removeData(myObj)
too.
Thanks for reading! Please share your thoughts with me on Twitter. Have a great day!
You’re not doing anything more with the thisArg, should those event bindings be using jQuery.proxy()? Of course that would complicate the unbinding since all the handlers would be wrapped in the same proxy function.
@Dave, Ah, thanks, I forgot to remove that. I think it’s best without. As you said, it would mean more confusion with unbinding.
You could reduce this code to:
The uselessness in all of this is now more evident.
@Esailija, nice work! Why did you say it was useless? I actually find it quite useful.
Because it’s not actually doing anything, just giving different names to the methods. You can just directly use the jQuery methods with their original names:
@Esailija, it provides the convenience of not having to confusingly wrap
myApp
in a jQuery call.Not wrapping it in a jQuery yet requiring the use of
jQuery.removeData
on the object is probably more confusing.@Esailija, it can be confusing yes. I do prefer a holistic API (direct methods instead of re-wrapping with jQ every time) though. I guess `removeData` is optional. You could implement your own “destroy” method. What event system can avoid this?
For custom events that don’t require the jQuery custom event features (bubbling, preventdefault, delegation, namespaces etc);
Now when the object goes out of scope, so do the event listeners. It also
has the added benefit of not being stringly typed.
@Esailija, good points! I guess I didn’t think enough about the implications of using jQ.
Recently I used a similar approach of using jQuery events, until I was faced with a rather peculiar bug in my app. When you trigger events on the object instance, jquery will also execute methods of that object which it thinks are event handlers.
What would you expect to happen in the following code:
Here’s a link to run that code: http://jsbin.com/amaxes/1
This behaviour was unexpected for me and caused quite a serious bug in my application. I have since decided it’s a bad idea to use jQuery events for non-dom objects.