Skip to content

Commit b2ea4c8

Browse files
crisbetojelbourn
authored andcommitted
fix(google-maps): avoid event listener leaks if inputs change (#17664)
Currently we initialize the map-related event listeners inside a subscription in the various map components, however the only time we remove them is on destroy. This can lead to leaks if the subcription fires multiple times. Note that at the moment we have a guard in place in the form of `take(1)`, but we could easily end up with event leaks if it were to be moved/removed if we decided to make it to react to changes post initialization.
1 parent 022acf8 commit b2ea4c8

File tree

3 files changed

+41
-9
lines changed

3 files changed

+41
-9
lines changed

src/google-maps/google-map/google-map.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy {
196196

197197
private _googleMapChanges!: Observable<google.maps.Map>;
198198

199-
private readonly _listeners: google.maps.MapsEventListener[] = [];
199+
private _listeners: google.maps.MapsEventListener[] = [];
200200

201201
private readonly _options = new BehaviorSubject<google.maps.MapOptions>(DEFAULT_OPTIONS);
202202
private readonly _center =
@@ -246,9 +246,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy {
246246
ngOnDestroy() {
247247
this._destroy.next();
248248
this._destroy.complete();
249-
for (let listener of this._listeners) {
250-
listener.remove();
251-
}
249+
this._clearListeners();
252250
}
253251

254252
/**
@@ -449,6 +447,9 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy {
449447
}
450448

451449
private _initializeEventHandlers() {
450+
// Ensure that we don't leak if called multiple times.
451+
this._clearListeners();
452+
452453
const eventHandlers = new Map<string, EventEmitter<void>>([
453454
['bounds_changed', this.boundsChanged],
454455
['center_changed', this.centerChanged],
@@ -493,4 +494,13 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy {
493494
}));
494495
}
495496
}
497+
498+
/** Clears all currently-registered event listeners. */
499+
private _clearListeners() {
500+
for (let listener of this._listeners) {
501+
listener.remove();
502+
}
503+
504+
this._listeners = [];
505+
}
496506
}

src/google-maps/map-info-window/map-info-window.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export class MapInfoWindow implements OnInit, OnDestroy {
8080
private readonly _position =
8181
new BehaviorSubject<google.maps.LatLngLiteral|google.maps.LatLng|undefined>(undefined);
8282

83-
private readonly _listeners: google.maps.MapsEventListener[] = [];
83+
private _listeners: google.maps.MapsEventListener[] = [];
8484

8585
private readonly _destroy = new Subject<void>();
8686

@@ -167,6 +167,9 @@ export class MapInfoWindow implements OnInit, OnDestroy {
167167
}
168168

169169
private _initializeEventHandlers() {
170+
// Ensure that we don't leak if called multiple times.
171+
this._clearListeners();
172+
170173
const eventHandlers = new Map<string, EventEmitter<void>>([
171174
['closeclick', this.closeclick],
172175
['content_changed', this.contentChanged],
@@ -182,4 +185,13 @@ export class MapInfoWindow implements OnInit, OnDestroy {
182185
}
183186
});
184187
}
188+
189+
/** Clears all currently-registered event listeners. */
190+
private _clearListeners() {
191+
for (let listener of this._listeners) {
192+
listener.remove();
193+
}
194+
195+
this._listeners = [];
196+
}
185197
}

src/google-maps/map-marker/map-marker.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ export class MapMarker implements OnInit, OnDestroy {
205205

206206
private readonly _destroy = new Subject<void>();
207207

208-
private readonly _listeners: google.maps.MapsEventListener[] = [];
208+
private _listeners: google.maps.MapsEventListener[] = [];
209209

210210
_marker?: google.maps.Marker;
211211

@@ -230,9 +230,7 @@ export class MapMarker implements OnInit, OnDestroy {
230230
ngOnDestroy() {
231231
this._destroy.next();
232232
this._destroy.complete();
233-
for (let listener of this._listeners) {
234-
listener.remove();
235-
}
233+
this._clearListeners();
236234
if (this._marker) {
237235
this._marker.setMap(null);
238236
}
@@ -390,6 +388,9 @@ export class MapMarker implements OnInit, OnDestroy {
390388
}
391389

392390
private _initializeEventHandlers() {
391+
// Ensure that we don't leak if called multiple times.
392+
this._clearListeners();
393+
393394
const eventHandlers = new Map<string, EventEmitter<void>>([
394395
['animation_changed', this.animationChanged],
395396
['clickable_changed', this.clickableChanged],
@@ -433,4 +434,13 @@ export class MapMarker implements OnInit, OnDestroy {
433434
}
434435
});
435436
}
437+
438+
/** Clears all currently-registered event listeners. */
439+
private _clearListeners() {
440+
for (let listener of this._listeners) {
441+
listener.remove();
442+
}
443+
444+
this._listeners = [];
445+
}
436446
}

0 commit comments

Comments
 (0)