Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Extract bindTo and unbindFromAll into Observer helper module

* Allows use of these helpers outside CompositeView
  • Loading branch information...
commit ff6666fad458e7418ff40bec3923f0641aee36bd 1 parent 589866d
@amkirwan amkirwan authored jferris committed
View
1  lib/assets/javascripts/backbone-support.js
@@ -1,2 +1,3 @@
//= require backbone-support/support
+//= require backbone-support/observer
//= require_tree ./backbone-support
View
15 lib/assets/javascripts/backbone-support/composite_view.js
@@ -1,10 +1,9 @@
Support.CompositeView = function(options) {
this.children = _([]);
- this.bindings = _([]);
Backbone.View.apply(this, [options]);
};
-_.extend(Support.CompositeView.prototype, Backbone.View.prototype, {
+_.extend(Support.CompositeView.prototype, Backbone.View.prototype, Support.Observer.prototype, {
leave: function() {
this.trigger('leave');
this.unbind();
@@ -14,18 +13,6 @@ _.extend(Support.CompositeView.prototype, Backbone.View.prototype, {
this._removeFromParent();
},
- bindTo: function(source, event, callback) {
- source.bind(event, callback, this);
- this.bindings.push({ source: source, event: event, callback: callback });
- },
-
- unbindFromAll: function() {
- this.bindings.each(function(binding) {
- binding.source.unbind(binding.event, binding.callback);
- });
- this.bindings = _([]);
- },
-
renderChild: function(view) {
view.render();
this.children.push(view);
View
16 lib/assets/javascripts/backbone-support/observer.js
@@ -0,0 +1,16 @@
+Support.Observer = function() {};
+
+_.extend(Support.Observer.prototype, {
+ bindTo: function(source, event, callback) {
+ source.bind(event, callback, this);
+ this.bindings = this.bindings || [];
+ this.bindings.push({ source: source, event: event, callback: callback });
+ },
+
+ unbindFromAll: function() {
+ _.each(this.bindings, function(binding) {
+ binding.source.unbind(binding.event, binding.callback);
+ });
+ this.bindings = []
+ }
+});
View
43 spec/javascripts/composite_view_spec.js
@@ -218,4 +218,47 @@ describe("Support.CompositeView", function() {
expect(eventListener.called).toBeTruthy();
});
});
+
+ describe("#bindTo", function() {
+ var view = new orangeView();
+ var callback = sinon.spy();
+ var source = new Backbone.Model({
+ title: 'Model or Collection'
+ });
+
+ it("calls the unbindFromAll method when leaving the view", function() {
+ view.bindTo(source, 'foobar', callback);
+ expect(view.bindings.length).toEqual(1);
+ });
+ });
+
+ describe("#unbindFromAll", function() {
+ var view = new orangeView();
+ var spy = sinon.spy(view, 'unbindFromAll');
+ var callback = sinon.spy();
+ var source = new Backbone.Model({
+ title: 'Model or Collection'
+ });
+
+ runs(function() {
+ view.render();
+ view.bindTo(source, 'foo', callback);
+ expect(view.bindings.length).toEqual(1);
+ });
+
+ Helpers.sleep();
+
+ runs(function() {
+ view.leave();
+ });
+
+ Helpers.sleep();
+
+ it("calls the unbindFromAll method when leaving the view", function() {
+ runs(function() {
+ expect(spy.called).toBeTruthy();
+ });
+ });
+ });
+
});
View
99 spec/javascripts/observer_spec.js
@@ -0,0 +1,99 @@
+describe('Support.Observer', function() {
+
+ var normalView = Support.CompositeView.extend({
+ render: function() {
+ var text = this.make("span", {}, "Normal!");
+ $(this.el).append(text);
+ },
+ leave: function() {
+ this.unbindFromAll();
+ }
+ });
+
+ beforeEach(function() {
+ Helpers.setup();
+ Helpers.append("test1");
+ Helpers.append("test2");
+ });
+
+ afterEach(function() {
+ Helpers.teardown();
+ });
+
+ describe("#bindTo", function() {
+ var view, spy, source, callback;
+ beforeEach(function() { Helpers.setup();
+ view = new normalView();
+ spy = sinon.spy(view, "bindTo");
+ callback = sinon.spy();
+
+ source = new Backbone.Model({
+ title: 'Model or Collection'
+ });
+ });
+
+ afterEach(function() {
+ view, spy, source, callback = null;
+ });
+
+ it("should add the event to the bindings for the view", function() {
+ view.bindTo(source, 'foobar', callback);
+ expect(view.bindings.length).toEqual(1);
+ });
+
+ it("binds the event to the source object", function() {
+ var mock = sinon.mock(source).expects('bind').once();
+
+ view.bindTo(source, 'change:title', callback);
+
+ mock.verify();
+ });
+ });
+
+ describe("#unbindFromAll", function() {
+ var view, spy, mock;
+ beforeEach(function() {
+ view = new normalView();
+ spy = sinon.spy(view, 'unbindFromAll');
+ callback = sinon.spy();
+ source = new Backbone.Model({
+ title: 'Model or Collection'
+ });
+ unbindSpy = sinon.spy(source, 'unbind');
+
+ runs(function() {
+ view.render();
+ view.bindTo(source, 'foo', callback);
+ view.bindTo(source, 'bar', callback);
+ expect(view.bindings.length).toEqual(2);
+ });
+
+ Helpers.sleep();
+
+ runs(function() {
+ view.leave();
+ });
+
+ Helpers.sleep();
+ });
+
+ it("calls the unbindFromAll method when leaving the view", function() {
+ runs(function() {
+ expect(spy.called).toBeTruthy();
+ });
+ });
+
+ it("calls unbind on the source object", function() {
+ runs(function() {
+ expect(unbindSpy.calledTwice).toBeTruthy();
+ });
+ });
+
+ it("removes all the views bindings attached with bindTo", function() {
+ runs(function() {
+ expect(view.bindings.length).toEqual(0);
+ });
+ });
+ });
+
+});
View
1  spec/javascripts/support/jasmine.yml
@@ -16,6 +16,7 @@ src_files:
- vendor/backbone.js
- lib/assets/javascripts/backbone-support.js
- lib/assets/javascripts/backbone-support/support.js
+ - lib/assets/javascripts/backbone-support/observer.js
- lib/**/*.js
# spec_files
Please sign in to comment.
Something went wrong with that request. Please try again.