jQuery Widget factory vs. my Controller factory
Posted by stephen on June 15th, 2011I’ve been working on a stateful/event driven model for jQuery “widgets” for a while now. For the sake of differentiating theirs and mine in this article, I’ll call mine the “controller” factory. I read the jQuery widget factory post a while back and basically dismissed/forgot about it at the time — not sure why. I stumbled onto it again today and wished I’d become accustomed to using it before creating my own, but I have some thoughts on it. Mine is more complicated without much added benefit, so I really like the simplicity of the widget factory.
My main complaint is probably pretty common, but since it’s not voiced on the post, I’ll do it here. There are no comments on their article, which makes me suspect the author is not moderating comments, and posting it there would be no good. Anyways, onto the meat…
General organization and instantiation
There should be support for multiple namespaces, and isolation of the widgets. When developing a website for multiple countries and locales with a large set of encapsulated and overlapping functional requirements, the hierarchy gets pretty complex, and without proper namespacing, my opinion is that it gets plain ugly. Simple sites can have simple namespaces, so namespacing should not make something more complex than it needs to be. For my controller factory, I have something like:
$("selector").controller(namespace.subns.ClassName, options);
Another difference is that I return the class instance so that it can be interacted with in the standard js manner, i.e.:
$("selector").controller(namespace.subns.Classname).controllerMethod(1,2,3);
I’m not sure which I like more, but I do like that the widget factory keeps the chainability of the jQuery methods. In my controller factory, I’ve proxied all of the jQuery methods on the base controller class to allow for this, but there’s merging and conflict possibilities with the controller prototype that I don’t like.
Events
I love that you can allow callbacks to be passed the widget factory as a property of the options parameter, then use their _trigger method to magically call the callback function and dispatch an event with that name. I think the benefit of a callback function is that it’s the first “handler” called after the method, so the caller of a method can have dibs on the initial response. The only deficit of a callback I can think of is that it’s not actually part of the event chain, which is petty.
My controller factory provides a “createDispatcher” method that creates a proxy function which dispatches an event. In other words, in the constructor of my controller I’ll create an “init” dispatcher with:
this.createDispatcher({init:"_init"});
That will result in a this.init() method that dispatches an “init” event (with the class name as the event namespace), and the “_init” method is bound as the first handler for that event. This way, even the method of the current instance is part of the event chain.
In addition, you can pass events to dispatch before and after the primary dispatcher.
this.createDispatcher({init:"_init", beforeInit:"_beforeInit", afterInit:"_afterInit"});
If the result of beforeInit is false, init will not be called (sort of like a bubble); otherwise, the beforeInit event object is attached to the init event object for reference. The same applies for the init and afterInit events (if one is false, the next doesn’t fire).
A huge benefit of the event proxy method is that extension classes can simply override the _init, _beforeInit, etc methods and still apply the “super” class’s method without worrying about it dispatching the event. In other words, say you have a Person class and a Child class.
Child.prototype._init = function(){
Person._init.apply(this, arguments);
};
That will work. If you’re dispatching events from directly within the method, as with the widget factory, trying to apply a super class’s method will dispatch god knows what events. Then, if you can’t work with that, you’ll have to copy all of the logic to your overriding method and dispatch the event where you want, and that’s a waste of reusable code.
Recent Comments