diff --git a/addon/components/g-map.js b/addon/components/g-map.js index 9d5e4bd8..1df31da8 100644 --- a/addon/components/g-map.js +++ b/addon/components/g-map.js @@ -15,7 +15,7 @@ function GMapPublicAPI(source) { }, get components() { - return source.components; + return source.deprecatedPublicComponents; }, }; } @@ -23,7 +23,7 @@ function GMapPublicAPI(source) { export default class GMap extends MapComponent { @tracked canvas; - components = {}; + components = new Set(); get publicAPI() { return GMapPublicAPI(this); @@ -106,15 +106,42 @@ export default class GMap extends MapComponent { this.canvas = canvas; } - // TODO: Return remove function @action getComponent(component, as = 'other') { - let components = this.components[as] ?? []; + let storedComponent = { component, as }; + this.components.add(storedComponent); + + this.addToDeprecatedPublicComponents(storedComponent); + + return { + context: this.publicAPI, + remove: () => { + this.components.delete(storedComponent); + this.removeFromDeprecatedPublicComponents(storedComponent); + }, + }; + } + + // TODO Deprecate access to this and replace with API methods. + deprecatedPublicComponents = {}; - components.push(component); + addToDeprecatedPublicComponents({ as, component }) { + if (!(as in this.deprecatedPublicComponents)) { + this.deprecatedPublicComponents[as] = []; + } - this.components[as] ??= components; + this.deprecatedPublicComponents[as].push(component); + } + + removeFromDeprecatedPublicComponents({ as, component }) { + let group = this.deprecatedPublicComponents[as]; + let index = group.indexOf(component); + + if (index > -1) { + group.splice(index, 1); + } - return this.publicAPI; + // For backwards compatibility, we don't remove the groups when they're + // empty. } } diff --git a/addon/components/g-map/map-component.js b/addon/components/g-map/map-component.js index e9631726..ad6f7dc4 100644 --- a/addon/components/g-map/map-component.js +++ b/addon/components/g-map/map-component.js @@ -60,10 +60,17 @@ export default class MapComponent { if (mapComponent) { mapComponent.setMap?.(null); } + + // Unregister from the parent component + this.onTeardown?.(); } register() { - this.context = this.args.getContext?.(this.publicAPI, this.name); + if (typeof this.args.getContext === 'function') { + let { context, remove } = this.args.getContext(this.publicAPI, this.name); + this.context = context; + this.onTeardown = remove; + } } /* Events */ diff --git a/tests/integration/components/g-map/marker-test.js b/tests/integration/components/g-map/marker-test.js index 5467e45a..a85089ca 100644 --- a/tests/integration/components/g-map/marker-test.js +++ b/tests/integration/components/g-map/marker-test.js @@ -63,4 +63,30 @@ module('Integration | Component | g map/marker', function (hooks) { assert.equal(marker.draggable, true); }); + + test('it unregisters a marker on teardown', async function (assert) { + assert.expect(2); + + this.set('showMarker', true); + + await render(hbs` + + {{#if this.showMarker}} + + {{/if}} + + `); + + let { + components: { markers }, + } = await this.waitForMap(); + + assert.equal(markers.length, 1, 'marker registered'); + + this.set('showMarker', false); + await this.waitForMap(); + + // This tests makes sure that the markers array is updated. + assert.equal(markers.length, 0, 'marker unregistered'); + }); });