Skip to content

fix(google-maps): internal events run inside NgZone #18034

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/google-maps/google-map/google-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
Optional,
Inject,
PLATFORM_ID,
NgZone,
} from '@angular/core';
import {isPlatformBrowser} from '@angular/common';
import {BehaviorSubject, combineLatest, Observable, Subject} from 'rxjs';
Expand Down Expand Up @@ -64,7 +65,7 @@ export const DEFAULT_WIDTH = '500px';
encapsulation: ViewEncapsulation.None,
})
export class GoogleMap implements OnChanges, OnInit, OnDestroy {
private _eventManager = new MapEventManager();
private _eventManager: MapEventManager = new MapEventManager(this._ngZone);
private _googleMapChanges: Observable<google.maps.Map>;

private readonly _options = new BehaviorSubject<google.maps.MapOptions>(DEFAULT_OPTIONS);
Expand Down Expand Up @@ -223,6 +224,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy {

constructor(
private readonly _elementRef: ElementRef,
private _ngZone: NgZone,
/**
* @deprecated `platformId` parameter to become required.
* @breaking-change 10.0.0
Expand Down Expand Up @@ -454,7 +456,12 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy {
Observable<google.maps.Map> {
return optionsChanges.pipe(
take(1),
map(options => new google.maps.Map(this._mapEl, options)),
map(options => {
// Create the object outside the zone so its events don't trigger change detection.
// We'll bring it back in inside the `MapEventManager` only for the events that the
// user has subscribed to.
return this._ngZone.runOutsideAngular(() => new google.maps.Map(this._mapEl, options));
}),
shareReplay(1));
}

Expand Down
7 changes: 6 additions & 1 deletion src/google-maps/map-event-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {NgZone} from '@angular/core';
import {Observable, Subscriber} from 'rxjs';

type MapEventManagerTarget = {
Expand All @@ -28,6 +29,8 @@ export class MapEventManager {
this._listeners = [];
}

constructor(private _ngZone: NgZone) {}

/** Gets an observable that adds an event listener to the map when a consumer subscribes to it. */
getLazyEmitter<T>(name: string): Observable<T> {
const observable = new Observable<T>(observer => {
Expand All @@ -37,7 +40,9 @@ export class MapEventManager {
return undefined;
}

const listener = this._target.addListener(name, (event: T) => observer.next(event));
const listener = this._target.addListener(name, (event: T) => {
this._ngZone.run(() => observer.next(event));
});
this._listeners.push(listener);
return () => listener.remove();
});
Expand Down
14 changes: 11 additions & 3 deletions src/google-maps/map-info-window/map-info-window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
OnDestroy,
OnInit,
Output,
NgZone,
} from '@angular/core';
import {BehaviorSubject, combineLatest, Observable, Subject} from 'rxjs';
import {map, takeUntil} from 'rxjs/operators';
Expand All @@ -33,7 +34,7 @@ import {MapEventManager} from '../map-event-manager';
host: {'style': 'display: none'},
})
export class MapInfoWindow implements OnInit, OnDestroy {
private _eventManager = new MapEventManager();
private _eventManager = new MapEventManager(this._ngZone);
private readonly _options = new BehaviorSubject<google.maps.InfoWindowOptions>({});
private readonly _position =
new BehaviorSubject<google.maps.LatLngLiteral|google.maps.LatLng|undefined>(undefined);
Expand Down Expand Up @@ -87,15 +88,22 @@ export class MapInfoWindow implements OnInit, OnDestroy {
zindexChanged: Observable<void> = this._eventManager.getLazyEmitter<void>('zindex_changed');

constructor(private readonly _googleMap: GoogleMap,
private _elementRef: ElementRef<HTMLElement>) {}
private _elementRef: ElementRef<HTMLElement>,
private _ngZone: NgZone) {}

ngOnInit() {
if (this._googleMap._isBrowser) {
this._combineOptions().pipe(takeUntil(this._destroy)).subscribe(options => {
if (this._infoWindow) {
this._infoWindow.setOptions(options);
} else {
this._infoWindow = new google.maps.InfoWindow(options);
// Create the object outside the zone so its events don't trigger change detection.
// We'll bring it back in inside the `MapEventManager` only for the events that the
// user has subscribed to.
this._ngZone.runOutsideAngular(() => {
this._infoWindow = new google.maps.InfoWindow(options);
});

this._eventManager.setTarget(this._infoWindow);
}
});
Expand Down
16 changes: 11 additions & 5 deletions src/google-maps/map-marker/map-marker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import {
OnDestroy,
OnInit,
Output,
ViewEncapsulation
ViewEncapsulation,
NgZone
} from '@angular/core';
import {BehaviorSubject, combineLatest, Observable, Subject} from 'rxjs';
import {map, take, takeUntil} from 'rxjs/operators';
Expand All @@ -43,7 +44,7 @@ export const DEFAULT_MARKER_OPTIONS = {
encapsulation: ViewEncapsulation.None,
})
export class MapMarker implements OnInit, OnDestroy {
private _eventManager = new MapEventManager();
private _eventManager = new MapEventManager(this._ngZone);
private readonly _options =
new BehaviorSubject<google.maps.MarkerOptions>(DEFAULT_MARKER_OPTIONS);
private readonly _title = new BehaviorSubject<string|undefined>(undefined);
Expand Down Expand Up @@ -236,15 +237,20 @@ export class MapMarker implements OnInit, OnDestroy {

_marker?: google.maps.Marker;

constructor(private readonly _googleMap: GoogleMap) {}
constructor(
private readonly _googleMap: GoogleMap,
private _ngZone: NgZone) {}

ngOnInit() {
if (this._googleMap._isBrowser) {
const combinedOptionsChanges = this._combineOptions();

combinedOptionsChanges.pipe(take(1)).subscribe(options => {
this._marker = new google.maps.Marker(options);
this._marker.setMap(this._googleMap._googleMap);
// Create the object outside the zone so its events don't trigger change detection.
// We'll bring it back in inside the `MapEventManager` only for the events that the
// user has subscribed to.
this._ngZone.runOutsideAngular(() => this._marker = new google.maps.Marker(options));
this._marker!.setMap(this._googleMap._googleMap);
this._eventManager.setTarget(this._marker);
});

Expand Down
12 changes: 9 additions & 3 deletions src/google-maps/map-polyline/map-polyline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
OnDestroy,
OnInit,
Output,
NgZone,
} from '@angular/core';
import {BehaviorSubject, combineLatest, Observable, Subject} from 'rxjs';
import {map, take, takeUntil} from 'rxjs/operators';
Expand All @@ -30,7 +31,7 @@ import {MapEventManager} from '../map-event-manager';
selector: 'map-polyline',
})
export class MapPolyline implements OnInit, OnDestroy {
private _eventManager = new MapEventManager();
private _eventManager = new MapEventManager(this._ngZone);
private readonly _options = new BehaviorSubject<google.maps.PolylineOptions>({});
private readonly _path =
new BehaviorSubject<google.maps.MVCArray<google.maps.LatLng>|google.maps.LatLng[]|
Expand Down Expand Up @@ -129,14 +130,19 @@ export class MapPolyline implements OnInit, OnDestroy {
polylineRightclick: Observable<google.maps.PolyMouseEvent> =
this._eventManager.getLazyEmitter<google.maps.PolyMouseEvent>('rightclick');

constructor(private readonly _map: GoogleMap) {}
constructor(
private readonly _map: GoogleMap,
private _ngZone: NgZone) {}

ngOnInit() {
if (this._map._isBrowser) {
const combinedOptionsChanges = this._combineOptions();

combinedOptionsChanges.pipe(take(1)).subscribe(options => {
this._polyline = new google.maps.Polyline(options);
// Create the object outside the zone so its events don't trigger change detection.
// We'll bring it back in inside the `MapEventManager` only for the events that the
// user has subscribed to.
this._ngZone.runOutsideAngular(() => this._polyline = new google.maps.Polyline(options));
this._polyline.setMap(this._map._googleMap);
this._eventManager.setTarget(this._polyline);
});
Expand Down
8 changes: 4 additions & 4 deletions tools/public_api_guard/google-maps/google-maps.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export declare class GoogleMap implements OnChanges, OnInit, OnDestroy {
width: string | number;
zoom: number;
zoomChanged: Observable<void>;
constructor(_elementRef: ElementRef,
constructor(_elementRef: ElementRef, _ngZone: NgZone,
platformId?: Object);
fitBounds(bounds: google.maps.LatLngBounds | google.maps.LatLngBoundsLiteral, padding?: number | google.maps.Padding): void;
getBounds(): google.maps.LatLngBounds | null;
Expand Down Expand Up @@ -63,7 +63,7 @@ export declare class MapInfoWindow implements OnInit, OnDestroy {
position: google.maps.LatLngLiteral | google.maps.LatLng;
positionChanged: Observable<void>;
zindexChanged: Observable<void>;
constructor(_googleMap: GoogleMap, _elementRef: ElementRef<HTMLElement>);
constructor(_googleMap: GoogleMap, _elementRef: ElementRef<HTMLElement>, _ngZone: NgZone);
close(): void;
getContent(): string | Node;
getPosition(): google.maps.LatLng | null;
Expand Down Expand Up @@ -103,7 +103,7 @@ export declare class MapMarker implements OnInit, OnDestroy {
titleChanged: Observable<void>;
visibleChanged: Observable<void>;
zindexChanged: Observable<void>;
constructor(_googleMap: GoogleMap);
constructor(_googleMap: GoogleMap, _ngZone: NgZone);
getAnimation(): google.maps.Animation | null;
getClickable(): boolean;
getCursor(): string | null;
Expand Down Expand Up @@ -137,7 +137,7 @@ export declare class MapPolyline implements OnInit, OnDestroy {
polylineMouseover: Observable<google.maps.PolyMouseEvent>;
polylineMouseup: Observable<google.maps.PolyMouseEvent>;
polylineRightclick: Observable<google.maps.PolyMouseEvent>;
constructor(_map: GoogleMap);
constructor(_map: GoogleMap, _ngZone: NgZone);
getDraggable(): boolean;
getEditable(): boolean;
getPath(): google.maps.MVCArray<google.maps.LatLng>;
Expand Down