Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Add Events#listenToOnce #2049

Merged
merged 3 commits into from
@gsamokovarov

As per discussion in #2045, I implemented oneTimeListenTo, an inversion-of-control version of once. @caseywebdev and @tgriesser voted for the name listenToOnce, but I went with oneTimeListenTo as it sounds clearer to me, but its up for discussion. If you guys like listenToOnce or some other name, I can change it.

Edit:

Changed the name from oneTimeListenTo to onceListenTo. Its still up for discussion, though.

Edit:

Changed to listenToOnce as per the comments.

@philfreo

I'd prefer listenToOnce (or even onceListenTo) so it parallels once, rather than using "oneTime"

@AjaxSolutions

Using 'once' in the method name is more consistent and shorter.

@tbranyen
Collaborator

Here we go again with a thread about naming, but I'd prefer listenToOnce :-p

@gsamokovarov

Fair enough. I like onceListenTo its easier to type and it keeps the once reference in there.

@tgriesser
Collaborator

I'm with @tbranyen and @philfreo on listenToOnce

@gsamokovarov

I still kinda want to keep the to at the end. Its consistent with how listenTo reads in code. But if most of you like listenToOnce, so be it :smile:

@akre54
Collaborator

also pitching in with @tbranyen and @philfreo. I think the semantics of listenToOnce aren't that awkward (or are at least much less awkward than onceListenTo)

@gsamokovarov

Have to agree with you. onceListenTo sounds kind of ambiguous. Will wait for the other guys to chime in before amending the last commit.

@caseywebdev
Collaborator

:+1: listenToOnce

@eastridge

+1 listenToOnce

@gsamokovarov

listenToOnce it is :smile:

@philfreo

:+1: on this (or some other way to easily clean up once events)

@Yahasana

listenOnce :100:

@caseywebdev
Collaborator

It needs the To to imply the first argument :wink:

@grydstedt

+1 listenToOnce!

@gsamokovarov

Rebased this one, so it can be applied cleanly to the current tree.

@tgriesser
Collaborator

@jashkenas - any opinion on this one? It does make the Event listeners symmetrical...

@jashkenas
Owner

Fun implementation and nice API symmetry, but I'm a little concerned if anyone will actually find it useful. Would y'all use this?

@philfreo

@jashkenas yes -- with listenTo now it's much more rare for me to have to manually cleanup listeners in View#remove now. But there's no automatic way to do that with once events (which I do use), and this fixes that

@dgbeck

I have not yet found occation for "once" events. A chained interaction perhaps where the second part depends on first, like choosing item from popup menu?

@akre54
Collaborator

I have once in a number of places where I want the callback removed after the event has been triggered, before the once event was introduced, I had at least a dozen places in code with code like

foo.on('closePopup', function() {
  doSomething();
  foo.off('closePopup')
});

a listenToOnce event would be a great help for me.

@tbranyen
Collaborator

Found myself needing this today:

this.listenToOnce(this.filters, "change", function() {
  this.filters.add(new Filter.Model());
});

I don't want to add a new filter every single time one has changed, I only ever add one once.

@ricogallo

@jashkenas I'm going to use this like that:

this.listenToOnce(this.model, signedEvent, function() {
  // do stuff;
});

:+1:

@jashkenas jashkenas merged commit 4d6b813 into jashkenas:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 47 additions and 11 deletions.
  1. +14 −10 backbone.js
  2. +33 −1 test/events.js
View
24 backbone.js
@@ -189,16 +189,6 @@
return this;
},
- // An inversion-of-control version of `on`. Tell *this* object to listen to
- // an event in another object ... keeping track of what it's listening to.
- listenTo: function(obj, name, callback) {
- var listeners = this._listeners || (this._listeners = {});
- var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
- listeners[id] = obj;
- obj.on(name, typeof name === 'object' ? this : callback, this);
- return this;
- },
-
// Tell this object to stop listening to either specific events ... or
// to every object it's currently listening to.
stopListening: function(obj, name, callback) {
@@ -218,6 +208,20 @@
}
};
+ var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
+
+ // An inversion-of-control versions of `on` and `once`. Tell *this* object to listen to
+ // an event in another object ... keeping track of what it's listening to.
+ _.each(listenMethods, function(eventBinder, method) {
+ Events[method] = function(obj, name, callback) {
+ var listeners = this._listeners || (this._listeners = {});
+ var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
+ listeners[id] = obj;
+ obj[eventBinder](name, typeof name === 'object' ? this : callback, this);
+ return this;
+ };
+ });
+
// Aliases for backwards compatibility.
Events.bind = Events.on;
Events.unbind = Events.off;
View
34 test/events.js
@@ -101,6 +101,38 @@ $(document).ready(function() {
b.trigger('event event2');
});
+ test("listenToOnce and stopListening", 1, function() {
+ var a = _.extend({}, Backbone.Events);
+ var b = _.extend({}, Backbone.Events);
+ a.listenToOnce(b, 'all', function() { ok(true); });
+ b.trigger('anything');
+ b.trigger('anything');
+ a.listenToOnce(b, 'all', function() { ok(false); });
+ a.stopListening();
+ b.trigger('anything');
+ });
+
+ test("listenTo, listenToOnce and stopListening", 1, function() {
+ var a = _.extend({}, Backbone.Events);
+ var b = _.extend({}, Backbone.Events);
+ a.listenToOnce(b, 'all', function() { ok(true); });
+ b.trigger('anything');
+ b.trigger('anything');
+ a.listenTo(b, 'all', function() { ok(false); });
+ a.stopListening();
+ b.trigger('anything');
+ });
+
+ test("listenTo and stopListening with event maps", 1, function() {
+ var a = _.extend({}, Backbone.Events);
+ var b = _.extend({}, Backbone.Events);
+ a.listenTo(b, {change: function(){ ok(true); }});
+ b.trigger('change');
+ a.listenTo(b, {change: function(){ ok(false); }});
+ a.stopListening();
+ b.trigger('change');
+ });
+
test("listenTo yourself", 1, function(){
var e = _.extend({}, Backbone.Events);
e.listenTo(e, "foo", function(){ ok(true); });
@@ -400,4 +432,4 @@ $(document).ready(function() {
_.extend({}, Backbone.Events).once('event').trigger('event');
});
-});
+});
Something went wrong with that request. Please try again.