Skip to content

Commit 056f89e

Browse files
committed
refactor(google-maps): allow event manager to handle native events
Updates the `MapEventManager` to support native events, in addition to the native ones from Google Maps.
1 parent c5f9a60 commit 056f89e

File tree

1 file changed

+36
-8
lines changed

1 file changed

+36
-8
lines changed

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

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,27 @@ import {NgZone} from '@angular/core';
1010
import {BehaviorSubject, Observable, Subscriber} from 'rxjs';
1111
import {switchMap} from 'rxjs/operators';
1212

13+
interface ListenerHandle {
14+
remove(): void;
15+
}
16+
1317
type MapEventManagerTarget =
1418
| {
1519
addListener<T extends unknown[]>(
1620
name: string,
1721
callback: (...args: T) => void,
1822
): google.maps.MapsEventListener | undefined;
23+
24+
addEventListener?<T extends unknown[]>(name: string, callback: (...args: T) => void): void;
25+
removeEventListener?<T extends unknown[]>(name: string, callback: (...args: T) => void): void;
1926
}
2027
| undefined;
2128

2229
/** Manages event on a Google Maps object, ensuring that events are added only when necessary. */
2330
export class MapEventManager {
2431
/** Pending listeners that were added before the target was set. */
2532
private _pending: {observable: Observable<unknown>; observer: Subscriber<unknown>}[] = [];
26-
private _listeners: google.maps.MapsEventListener[] = [];
33+
private _listeners: ListenerHandle[] = [];
2734
private _targetStream = new BehaviorSubject<MapEventManagerTarget>(undefined);
2835

2936
/** Clears all currently-registered event listeners. */
@@ -37,8 +44,12 @@ export class MapEventManager {
3744

3845
constructor(private _ngZone: NgZone) {}
3946

40-
/** Gets an observable that adds an event listener to the map when a consumer subscribes to it. */
41-
getLazyEmitter<T>(name: string): Observable<T> {
47+
/**
48+
* Gets an observable that adds an event listener to the map when a consumer subscribes to it.
49+
* @param name Name of the event for which the observable is being set up.
50+
* @param type Type of the event (e.g. one going to a DOM node or a custom Maps one).
51+
*/
52+
getLazyEmitter<T>(name: string, type?: 'custom' | 'native'): Observable<T> {
4253
return this._targetStream.pipe(
4354
switchMap(target => {
4455
const observable = new Observable<T>(observer => {
@@ -48,19 +59,36 @@ export class MapEventManager {
4859
return undefined;
4960
}
5061

51-
const listener = target.addListener(name, (event: T) => {
62+
let handle: ListenerHandle;
63+
const listener = (event: T) => {
5264
this._ngZone.run(() => observer.next(event));
53-
});
65+
};
66+
67+
if (type === 'native') {
68+
if (
69+
(typeof ngDevMode === 'undefined' || ngDevMode) &&
70+
(!target.addEventListener || !target.removeEventListener)
71+
) {
72+
throw new Error(
73+
'Maps event target that uses native events must have `addEventListener` and `removeEventListener` methods.',
74+
);
75+
}
76+
77+
target.addEventListener!(name, listener);
78+
handle = {remove: () => target.removeEventListener!(name, listener)};
79+
} else {
80+
handle = target.addListener(name, listener)!;
81+
}
5482

5583
// If there's an error when initializing the Maps API (e.g. a wrong API key), it will
5684
// return a dummy object that returns `undefined` from `addListener` (see #26514).
57-
if (!listener) {
85+
if (!handle) {
5886
observer.complete();
5987
return undefined;
6088
}
6189

62-
this._listeners.push(listener);
63-
return () => listener.remove();
90+
this._listeners.push(handle);
91+
return () => handle.remove();
6492
});
6593

6694
return observable;

0 commit comments

Comments
 (0)