Skip to content

Instantly share code, notes, and snippets.

@davemo
Created May 3, 2011 21:43
Show Gist options
  • Save davemo/954329 to your computer and use it in GitHub Desktop.
Save davemo/954329 to your computer and use it in GitHub Desktop.
A way to add declarative bindings using jQuery and a simple module pattern.
// Given a simplified module pattern like so:
(function(APP, $, _) {
APP.MyWidget = function(opts) {
var self = {};
var defaults = {
// an array of contexts and declarative event bindings
bindings : [
{
// selector of the element events will be delegated to, the "context"
'#my-widget' : {
// declarative event bindings hash with a pattern of 'event selector' : 'callback' (similar to backbone)
'click #view-chart' : 'viewChart',
'click #view-table' : 'viewTable',
'click #view-related-articles' : 'viewRelatedArticles',
'change #metrics' : 'handleMetricChange',
'focusout #search-chart' : 'queueResultsTimeout',
'click #addremove' : 'toggleAddRemoveEntities'
}
},
{
// a second context in which to bind events that exists in the same widget
'.add-remove-controls' : {
'click .close' : 'toggleAddRemoveEntities',
'click .result' : 'addEntity',
'click .remove' : 'removeEntity'
}
}
]
};
// mixin the user defined options to the defaults and assign to self.opts
self.opts = $.extend(true, defaults, opts || {});
// the functions that will be called when events happen
self.viewChart = function() {};
self.viewTable = function() {};
self.viewRelatedArticles = function() {};
// ... etc
// an initializer, immediately invoked
self.init = (function() {
APP.Util.bindEvents(self, self.opts.bindings);
})();
return self;
};
})(APP, jQuery, _);
// And a util lib that has a bind function
(function(APP, $, _) {
APP.Util = {
bindEvents : function(obj, bindings) {
_.each(bindings, function(binding) {
var context = _.keys(binding)[0];
_.each(binding[context], function(callback, eventAndSelector) {
var parts = eventAndSelector.split(" ");
var event = parts[0];
var selector = parts[1];
APP.Util.delegateEventsInContext(context, selector, event, obj[callback]);
});
});
},
delegateEventsInContext : function(context, selector, event, callback) {
$(context).delegate(selector, event, callback);
}
};
})(APP, jQuery, _);
<!-- Leads to binding for a given context automatically, providing an easy interface for event delegation. -->
<div id="my-widget">
<a href="#" id="view-chart">View the Chart</a> <!-- I have a click event bound to call the function 'viewChart' -->
<a href="#" id="view-table">View the Table</a> <!-- I have a click event bound to call the function 'viewTable' -->
<ul class="add-remove-controls">
<li><a href="#" class="result">Canada</a></li> <!-- All these results have a click event bound to call 'handleResultClick' -->
<li><a href="#" class="result">Russia</a></li>
<li><a href="#" class="result">England</a></li>
<li><a href="#" class="result">United States</a></li>
<li><a href="#" class="result">Africa</a></li>
</ul>
</div>
@searls
Copy link

searls commented May 5, 2011

This is awesome. Love how brief it is and that I'd be able to incorporate this pattern without adopting an external dependency.

@davemo
Copy link
Author

davemo commented May 5, 2011

Sweet! Glad you like it :) I got some positive feedback from a random guy on twitter about it as well. The paradigm worked nice enough in backbone that it seemed easy to yoink.

@davemo
Copy link
Author

davemo commented Jun 29, 2011

Updated to support the declaration of multiple contexts for event delegation within a single widget.

@shihgianlee
Copy link

Maybe I am missing something. On line 61, I think the params are reversed. Shouldn't it be _.each(binding[context], function(eventAndSelector, callback)?

@davemo
Copy link
Author

davemo commented Jun 29, 2011

Nope, in the underscore docs for _.each "If list is a JavaScript object, iterator's arguments will be (value, key, list)." We're iterating over the object that maps to the context, so the params are (value, key) which equates to (callback, eventAndSelector). http://documentcloud.github.com/underscore/#each

@shihgianlee
Copy link

Thanks for the explanation! I didn't read the doc. carefully ;) It is a pretty cool code snippet!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment