Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #1 from jsoverson/jquery-support

added support for jQuery style objects
  • Loading branch information...
commit 49b8605f7c12e1fe6f7e93cf854504cae40b2780 2 parents a5cbd69 + edd2752
@jsoverson jsoverson authored
View
1  .gitignore
@@ -3,3 +3,4 @@
*.swo
node_modules
_SpecRunner.html
+.idea
View
26 readme.md
@@ -38,22 +38,38 @@ events, across any number of objects that trigger the events. This allows
events to be grouped together and unbound with a single call during the
clean-up of an object that is bound to the events.
+Ultimately, the EventBinder calls back to the standard Backbone `on` method
+of the object for which events are being handled. The benefit of using the
+EventBinder then, is that you no longer have to manually manage calling `off`
+for each of these events, and you can safely use anonymous callback functions
+as event arguments and stil be able to unbind them when needed.
+
### Bind Events
+The basic syntax for binding events is to use the `bindTo` method which
+follows the path of Backbone's `on` method for events, but adds one parameter
+to the beginning of the method call: the object that triggers the event.
+
+For example, if you have a model that you want to listen for events from,
+you can use the EventBinder to manage the event for you:
+
```js
var binder = new Backbone.EventBinder();
var model = new MyModel();
var handler = {
- doIt: function(){}
+ doIt: function(){ /* ... */ }
}
-binder.bindTo(model, "change:foo", handler.doIt);
+// same args list as model.on, but putting the model as the first parameter
+binder.bindTo(model, "change:foo", handler.doIt, handler);
```
-You can optionally specify a 4th parameter as the context in which the callback
-method for the event will be executed:
+You can specify a 4th parameter as the context in which the callback
+method for the event will be executed. If you leave the empty, the default
+context will be used (varies depending on other circumstances) just like
+Backbone's events.
```js
binder.bindTo(model, "change:foo", someCallback, someContext);
@@ -87,7 +103,7 @@ This even works with in-line callback functions.
### When To Use EventBinder vs `on` Handlers
-See the wiki: [When to use the EventBinder](https://github.com/marionettejs/backbone.marionette/wiki/When-to-use-the-EventBinder)
+See the wiki: [When to use the EventBinder](https://github.com/marionettejs/backbone.eventbinder/wiki/When-to-use-the-EventBinder)
## License
View
30 spec/javascripts/eventbinder.jquery.spec.js
@@ -0,0 +1,30 @@
+describe("When binding to a jQuery object", function(){
+
+ var binding, binder, element, handler;
+
+ beforeEach(function(){
+ handler = jasmine.createSpy().andCallFake(function(){
+ console.log('clicked')
+ });
+ binder = new Backbone.EventBinder();
+ element = $('<p></p>');
+ binding = binder.bindTo(element, "click", handler);
+ });
+
+ it("should store binding with type 'jquery'", function(){
+ expect(binding.type).toEqual('jquery');
+ });
+
+ it("should execute the handler upon simulated click", function(){
+ element.click();
+ expect(handler).toHaveBeenCalled();
+ });
+
+ it("should unbind handlers", function(){
+ binder.unbindAll();
+ element.click();
+ expect(handler).not.toHaveBeenCalled();
+ });
+
+});
+
View
2  spec/javascripts/eventbinder.spec.js
@@ -1,4 +1,4 @@
-describe("event binder", function(){
+describe("Default event binder logic", function(){
var Model = Backbone.Model;
describe("when binding an event", function(){
View
87 src/eventbinder.js
@@ -10,6 +10,64 @@
Backbone.EventBinder = (function(Backbone, _){
"use strict";
+
+ // A map of objects that support binding/unbinding events.
+ // This allows EventBinder to support events on arbitrary
+ // objects with EB's consistent api.
+ var handlerMap = {
+ // 'default' type accounts for Backbone style objects extending
+ // Backbone.Events
+ default : {
+ bindTo : function (obj, eventName, callback, context) {
+ context = context || this;
+ obj.on(eventName, callback, context);
+
+ var binding = {
+ type : 'default',
+ obj: obj,
+ eventName: eventName,
+ callback: callback,
+ context: context
+ };
+
+ return binding;
+ },
+ unbindFrom : function(binding){
+ binding.obj.off(binding.eventName, binding.callback, binding.context);
+ }
+ },
+
+ // 'jquery' style handlers allow us to bind to jQuery
+ // (or compatible) objects
+ jquery : {
+ bindTo : function (obj, eventName, callback, context) {
+ context = context || this;
+ callback = _(callback).bind(context);
+ obj.on(eventName, callback);
+
+ var binding = {
+ type : 'jquery',
+ obj: obj,
+ eventName: eventName,
+ callback: callback,
+ context: context
+ };
+
+ return binding;
+ },
+ unbindFrom : function(binding){
+ binding.obj.off(binding.eventName, binding.callback);
+ }
+ }
+ };
+
+ // Use whatever best logic necessary to determine the type
+ // of the supplied object
+ function getHandlerForObject(obj) {
+ if (obj.jquery) return handlerMap.jquery;
+
+ return handlerMap.default;
+ }
// Constructor function
var EventBinder = function(){
@@ -21,18 +79,15 @@ Backbone.EventBinder = (function(Backbone, _){
// Extend the EventBinder with additional methods
_.extend(EventBinder.prototype, {
- // Store the event binding in array so it can be unbound
+
+ // Delegate to the bindTo for the appropriate type and
+ // store the event binding in array so it can be unbound
// easily, at a later point in time.
- bindTo: function (obj, eventName, callback, context) {
- context = context || this;
- obj.on(eventName, callback, context);
+ bindTo: function(/* args... */) {
+ var obj = arguments[0];
+ var handlers = getHandlerForObject(obj);
- var binding = {
- obj: obj,
- eventName: eventName,
- callback: callback,
- context: context
- };
+ var binding = handlers.bindTo.apply(this,arguments);
this._eventBindings.push(binding);
@@ -41,21 +96,17 @@ Backbone.EventBinder = (function(Backbone, _){
// Unbind from a single binding object. Binding objects are
// returned from the `bindTo` method call.
- unbindFrom: function(binding){
- binding.obj.off(binding.eventName, binding.callback, binding.context);
+ unbindFrom: function(binding) {
+ handlerMap[binding.type].unbindFrom.apply(this,arguments);
this._eventBindings = _.reject(this._eventBindings, function(bind){return bind === binding;});
},
// Unbind all of the events that we have stored.
- unbindAll: function () {
- var that = this;
-
+ unbindAll: function() {
// The `unbindFrom` call removes elements from the array
// while it is being iterated, so clone it first.
var bindings = _.map(this._eventBindings, _.identity);
- _.each(bindings, function (binding, index) {
- that.unbindFrom(binding);
- });
+ _.each(bindings, this.unbindFrom, this);
}
});
Please sign in to comment.
Something went wrong with that request. Please try again.