I've been working almost exclusively with JavaScript building single page applications recently. jQuery has made developing the apps enjoyable but one area I find a bit awkward is creating complex objects.
Classes work well but can be cumbersome when creating a user interface since the object reference returned from the constructor is not a DOM node but a JavaScript object. Therefore, in order to insert the user interface component into the page, a special method like getHTML
must be available for that object. This isn't terrible but creates more complicated code. Here's an example user interface widget - a simple box displaying a name:
function Widget(name) {
var container = $("<div/>");
function setName(newName) {
name = newName;
container.html(name);
}
this.getHTML = function () {
setName(name);
return container;
};
this.getName = function () {
return name;
};
this.setName = function (newName) {
setName(name);
};
}
And the code that uses it:
var nameWidget = new Widget("Dave");
var widgetNode = nameWidget.getHTML();
$(document.body).append(widgetNode);
This isn't too bad but gets a bit ugly when you need the ability to hide, show, animate, or do anything interesting. The choice is either to attach more methods to the Widget
class or work with the jQuery object returned by getHTML
. Pattern-wise, adding more methods to Widget
is the cleanest but could require creating a lot of methods. Working with the jQuery object returned by getHTML
is easy but leads to managing two objects in your code: nameWidget
and widgetNode
What would be really nice is the ability to call any jQuery method on the nameWidget
object PLUS all the methods specific to the Widget
class. It occurred to me that this could be possible with the addition of a small jQuery Plugin I've dubbed Methods.
(function ($) {
$.fn.methods = function (arg0) {
if (arg0)
{
return this.each(function (i) {
$(this).data("methods", arg0);
});
}
else
{
return $(this).data("methods");
}
};
})(jQuery);
This plugin adds the methods
method to jQuery. A collection of functions can be passed to methods
to attach it to a specific jQuery object. Calling methods
then returns the collection of functions. Here's a rewrite of the Widget
class to explain this better:
function widget(tag, name) {
var container;
container = $(tag)
.html(name)
.methods({
getName: function () {
return name;
},
// Return "this" for chainability
setName: function (newName) {
name = newName;
container.html(name);
return this;
},
// Add the end method for chainability
end: function () {
return container;
}
});
return container;
}
And the code that uses this:
var nameWigdet = widget("<div/>", "Dave");
$(document.body).append(nameWidget);
Now we have a nameWidget
that directly corresponds to the user interface component and, using jQuery, can be inserted anywhere in the page. To access the object's specific methods, you simply call methods
. Here's an example that shows the combination of the methods and chaining:
nameWidget
.hide()
.methods()
.setName("Bob")
.end()
.show()
.addClass("widget");
Since the Methods plugin uses jQuery's data method behind the scenes, the nameWidget can actually be retrieved through a DOM lookup.
var nameWidget = $(".widget")
.hide()
.methods()
.setName("Sally")
.end()
.show();
And that's it. In the end, Methods is a simple jQuery plugin that lets you create complex objects with custom methods and closures and can still be used like a regular jQuery object.
No comments:
Post a Comment