diff --git a/src/ol/events/eventtarget.js b/src/ol/events/eventtarget.js index a32df51575..54a25cbd6b 100644 --- a/src/ol/events/eventtarget.js +++ b/src/ol/events/eventtarget.js @@ -33,6 +33,12 @@ ol.events.EventTarget = function() { */ this.pendingRemovals_ = {}; + /** + * @private + * @type {!Object.} + */ + this.dispatching_ = {}; + /** * @private * @type {!Object.>} @@ -72,19 +78,25 @@ ol.events.EventTarget.prototype.dispatchEvent = function(event) { var listeners = this.listeners_[type]; var propagate; if (listeners) { - if (!(type in this.pendingRemovals_)) { + if (!(type in this.dispatching_)) { + this.dispatching_[type] = 0; this.pendingRemovals_[type] = 0; } + ++this.dispatching_[type]; for (var i = 0, ii = listeners.length; i < ii; ++i) { if (listeners[i].call(this, evt) === false || evt.propagationStopped) { propagate = false; break; } } - var pendingRemovals = this.pendingRemovals_[type]; - delete this.pendingRemovals_[type]; - while (pendingRemovals--) { - this.removeEventListener(type, ol.nullFunction); + --this.dispatching_[type]; + if (this.dispatching_[type] === 0) { + var pendingRemovals = this.pendingRemovals_[type]; + delete this.pendingRemovals_[type]; + while (pendingRemovals--) { + this.removeEventListener(type, ol.nullFunction); + } + delete this.dispatching_[type]; } return propagate; } diff --git a/test/spec/ol/observable.test.js b/test/spec/ol/observable.test.js index 73b158f096..02925ebdb9 100644 --- a/test/spec/ol/observable.test.js +++ b/test/spec/ol/observable.test.js @@ -73,6 +73,21 @@ describe('ol.Observable', function() { expect(listener.callCount).to.be(1); }); + it('is safe to dispatch events of same type in a once listener', function() { + var callCount = 0; + observable.once('change', function() { + observable.changed(); + observable.changed(); + }); + observable.on('change', function() { + ++callCount; + }); + expect(function() { + observable.changed(); + }).to.not.throwException(); + expect(callCount).to.be(3); + }); + it('accepts an array of event types (called once for each)', function() { observable.once(['foo', 'bar'], listener);