@@ -10,20 +10,27 @@ import {NgZone} from '@angular/core';
10
10
import { BehaviorSubject , Observable , Subscriber } from 'rxjs' ;
11
11
import { switchMap } from 'rxjs/operators' ;
12
12
13
+ interface ListenerHandle {
14
+ remove ( ) : void ;
15
+ }
16
+
13
17
type MapEventManagerTarget =
14
18
| {
15
19
addListener < T extends unknown [ ] > (
16
20
name : string ,
17
21
callback : ( ...args : T ) => void ,
18
22
) : 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 ;
19
26
}
20
27
| undefined ;
21
28
22
29
/** Manages event on a Google Maps object, ensuring that events are added only when necessary. */
23
30
export class MapEventManager {
24
31
/** Pending listeners that were added before the target was set. */
25
32
private _pending : { observable : Observable < unknown > ; observer : Subscriber < unknown > } [ ] = [ ] ;
26
- private _listeners : google . maps . MapsEventListener [ ] = [ ] ;
33
+ private _listeners : ListenerHandle [ ] = [ ] ;
27
34
private _targetStream = new BehaviorSubject < MapEventManagerTarget > ( undefined ) ;
28
35
29
36
/** Clears all currently-registered event listeners. */
@@ -37,8 +44,12 @@ export class MapEventManager {
37
44
38
45
constructor ( private _ngZone : NgZone ) { }
39
46
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 > {
42
53
return this . _targetStream . pipe (
43
54
switchMap ( target => {
44
55
const observable = new Observable < T > ( observer => {
@@ -48,19 +59,36 @@ export class MapEventManager {
48
59
return undefined ;
49
60
}
50
61
51
- const listener = target . addListener ( name , ( event : T ) => {
62
+ let handle : ListenerHandle ;
63
+ const listener = ( event : T ) => {
52
64
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
+ }
54
82
55
83
// If there's an error when initializing the Maps API (e.g. a wrong API key), it will
56
84
// return a dummy object that returns `undefined` from `addListener` (see #26514).
57
- if ( ! listener ) {
85
+ if ( ! handle ) {
58
86
observer . complete ( ) ;
59
87
return undefined ;
60
88
}
61
89
62
- this . _listeners . push ( listener ) ;
63
- return ( ) => listener . remove ( ) ;
90
+ this . _listeners . push ( handle ) ;
91
+ return ( ) => handle . remove ( ) ;
64
92
} ) ;
65
93
66
94
return observable ;
0 commit comments