@@ -10,20 +10,27 @@ import {NgZone} from '@angular/core';
1010import { BehaviorSubject , Observable , Subscriber } from 'rxjs' ;
1111import { switchMap } from 'rxjs/operators' ;
1212
13+ interface ListenerHandle {
14+ remove ( ) : void ;
15+ }
16+
1317type 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. */
2330export 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