diff --git a/src/ol/interaction/Select.js b/src/ol/interaction/Select.js index 3bd762db51..a08c22bc54 100644 --- a/src/ol/interaction/Select.js +++ b/src/ol/interaction/Select.js @@ -259,9 +259,6 @@ class Select extends Interaction { * @type {Object} */ this.featureLayerAssociation_ = {}; - - this.features_.addEventListener(CollectionEventType.ADD, this.boundAddFeature_); - this.features_.addEventListener(CollectionEventType.REMOVE, this.boundRemoveFeature_); } /** @@ -329,8 +326,13 @@ class Select extends Interaction { this.features_.forEach(this.restorePreviousStyle_.bind(this)); } super.setMap(map); - if (map && this.style_) { - this.features_.forEach(this.applySelectedStyle_.bind(this)); + if (map) { + this.features_.addEventListener(CollectionEventType.ADD, this.boundAddFeature_); + this.features_.addEventListener(CollectionEventType.REMOVE, this.boundRemoveFeature_); + + if (this.style_) { + this.features_.forEach(this.applySelectedStyle_.bind(this)); + } } if (!map) { this.features_.removeEventListener(CollectionEventType.ADD, this.boundAddFeature_); diff --git a/test/spec/ol/interaction/select.test.js b/test/spec/ol/interaction/select.test.js index e64eb2dc28..65d47cea43 100644 --- a/test/spec/ol/interaction/select.test.js +++ b/test/spec/ol/interaction/select.test.js @@ -9,6 +9,7 @@ import Interaction from '../../../../src/ol/interaction/Interaction.js'; import Select from '../../../../src/ol/interaction/Select.js'; import VectorLayer from '../../../../src/ol/layer/Vector.js'; import VectorSource from '../../../../src/ol/source/Vector.js'; +import Style from '../../../../src/ol/style/Style.js'; describe('ol.interaction.Select', function() { @@ -406,4 +407,53 @@ describe('ol.interaction.Select', function() { }); }); + + describe('clear event listeners on interaction removal', function() { + let firstInteraction, secondInteraction, feature; + + beforeEach(function() { + feature = source.getFeatures()[3]; // top feature is selected + + const style = new Style({}); + const features = new Collection(); + + firstInteraction = new Select({ style, features }); + secondInteraction = new Select({ style, features }); + }); + + afterEach(function() { + map.removeInteraction(secondInteraction); + map.removeInteraction(firstInteraction); + }); + + // The base case + describe('with a single interaction added', function() { + it('changes the selected feature once', function() { + map.addInteraction(firstInteraction); + + const listenerSpy = sinon.spy(); + feature.on('change', listenerSpy); + + simulateEvent('singleclick', 10, -20, false); + + expect(listenerSpy.callCount).to.be(1); + }); + }); + + // The "difficult" case. To prevent regression + describe('with a replaced interaction', function() { + it('changes the selected feature once', function() { + map.addInteraction(firstInteraction); + map.removeInteraction(firstInteraction); + map.addInteraction(secondInteraction); + + const listenerSpy = sinon.spy(); + feature.on('change', listenerSpy); + + simulateEvent('singleclick', 10, -20, false); + + expect(listenerSpy.callCount).to.be(1); + }); + }); + }); });