Thursday, March 12th, 2009
Object Oriented Event Handling and Widgets
Paul Chiu, author of Passbook, has written up his thoughts on reuse for widgets in large Ajax applications.
The solution?
For Passbook I decided to solve this problem once and for all. The solution I believe is in objectifying page elements as a block so that a panel with an edit and delete button can be duplicated quickly without having the Javascript code keep track of which panel on the page was clicked and trying to modify that page element. An object oriented approach would mean the page object could edit or delete it self because it knows what it is and what it represents.
While there are some existing solutions that use custom methods to streamline the object oriented process and work around Javascript's event target scoping of "this". I believe a better method existed that did not require so much prototype modification and was more self contained and flexible. My solution is to use jQuery's plugin model to control on page elements, or widgets.
To see the basic pattern it is easiest to first checkout the functional demo. The demo contains two main elements: a widgets container where an add action exists, and a widget controller that offers the user the ability to submit it or remove it. The demo shows the widget manipulating it self, its parent, as well as using a basic ajax callback within it self.
Paul then walks through an example, that ends up with the following code.
(function($) {
// Widget container plugin
$.fn.widgetContainer = function() {
this.each(function() {
// Vars
var wc = $(this);
// Set events
wc.find('#add').click(function(e) { if (e) e.preventDefault(); add(wc) });
});
}
// Add a widget to the container
function add(wc) {
var widget = $($.fn.widget.template);
widget
.appendTo(wc)
.fadeIn('slow')
.widget(wc);
}
// Widget
(function() {
// Widget plugin
$.fn.widget = function(container) {
this.each(function() {
// Vars
var w = $(this);
w.parent = container;
// Set events
w.find('form').submit(function(e) { if (e) e.preventDefault(); submit(w) });
w.find('.remove').click(function(e) { if (e) e.preventDefault(); remove(w) });
});
}
$.fn.widget.template = '<div class="widget"><form action="" method="POST"><input type="text" value=""/><input type="submit" value="Action!"/><a href="#" class="remove">Remove</a></form></div>';
// Remove widget
function remove(w) {
w.remove();
}
// Submit widget data
function submit(w) {
w.css('background', 'red');
$.post('/', w.find('form').serialize(), function(data) {
w.find(':text').val((new Date()).toString());
w.parent.fadeOut();
setTimeout(function() { w.parent.fadeIn() }, 500);
});
}
})();
})(jQuery);
// Main
$(function() {
$('.widgetContainer').widgetContainer();
});







Leave a comment