From 4b63cfed037cfc12ce71ce8de78dc2e2d2f5f93e Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Tue, 9 Feb 2021 17:34:27 +0100 Subject: [PATCH] refactor(google-maps): clean up internal setup (#21079) Reworks the internal setup of the `google-map` component so that we don't have to declare observables for each input. (cherry picked from commit 28c36f8a02f72e51a4d6c6a797e2f913e5dede9b) --- src/google-maps/google-map/google-map.ts | 131 +++++++----------- .../google-maps/google-maps.d.ts | 2 +- 2 files changed, 52 insertions(+), 81 deletions(-) diff --git a/src/google-maps/google-map/google-map.ts b/src/google-maps/google-map/google-map.ts index 1c0daa457039..9ee0af4f59c6 100644 --- a/src/google-maps/google-map/google-map.ts +++ b/src/google-maps/google-map/google-map.ts @@ -22,10 +22,10 @@ import { Inject, PLATFORM_ID, NgZone, + SimpleChanges, } from '@angular/core'; import {isPlatformBrowser} from '@angular/common'; -import {BehaviorSubject, combineLatest, Observable, Subject} from 'rxjs'; -import {map, shareReplay, take, takeUntil} from 'rxjs/operators'; +import {Observable} from 'rxjs'; import {MapEventManager} from '../map-event-manager'; interface GoogleMapsWindow extends Window { @@ -57,13 +57,6 @@ export const DEFAULT_WIDTH = '500px'; }) export class GoogleMap implements OnChanges, OnInit, OnDestroy { private _eventManager: MapEventManager = new MapEventManager(this._ngZone); - private _googleMapChanges: Observable; - - private readonly _options = new BehaviorSubject(DEFAULT_OPTIONS); - private readonly _center = - new BehaviorSubject(undefined); - private readonly _zoom = new BehaviorSubject(undefined); - private readonly _destroy = new Subject(); private _mapEl: HTMLElement; /** @@ -90,16 +83,21 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { @Input() set center(center: google.maps.LatLngLiteral|google.maps.LatLng) { - this._center.next(center); + this._center = center; } + private _center: google.maps.LatLngLiteral|google.maps.LatLng; + @Input() set zoom(zoom: number) { - this._zoom.next(zoom); + this._zoom = zoom; } + private _zoom: number; + @Input() set options(options: google.maps.MapOptions) { - this._options.next(options || DEFAULT_OPTIONS); + this._options = options || DEFAULT_OPTIONS; } + private _options = DEFAULT_OPTIONS; /** * See @@ -246,10 +244,30 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { } } - ngOnChanges() { - this._setSize(); - if (this.googleMap && this.mapTypeId) { - this.googleMap.setMapTypeId(this.mapTypeId); + ngOnChanges(changes: SimpleChanges) { + if (changes['height'] || changes['width']) { + this._setSize(); + } + + const googleMap = this.googleMap; + + if (googleMap) { + if (changes['options'] && this._options) { + googleMap.setOptions(this._options); + } + + if (changes['center'] && this._center) { + googleMap.setCenter(this._center); + } + + // Note that the zoom can be zero. + if (changes['zoom'] && this._zoom != null) { + googleMap.setZoom(this._zoom); + } + + if (changes['mapTypeId'] && this.mapTypeId) { + googleMap.setMapTypeId(this.mapTypeId); + } } } @@ -258,22 +276,19 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { if (this._isBrowser) { this._mapEl = this._elementRef.nativeElement.querySelector('.map-container')!; this._setSize(); - this._googleMapChanges = this._initializeMap(this._combineOptions()); - this._googleMapChanges.subscribe((googleMap: google.maps.Map) => { - this.googleMap = googleMap; - this._eventManager.setTarget(this.googleMap); - }); - this._watchForOptionsChanges(); - this._watchForCenterChanges(); - this._watchForZoomChanges(); + // 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.googleMap = new google.maps.Map(this._mapEl, this._combineOptions()); + }); + this._eventManager.setTarget(this.googleMap); } } ngOnDestroy() { this._eventManager.destroy(); - this._destroy.next(); - this._destroy.complete(); } /** @@ -443,60 +458,16 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { } /** Combines the center and zoom and the other map options into a single object */ - private _combineOptions(): Observable { - return combineLatest([this._options, this._center, this._zoom]) - .pipe(map(([options, center, zoom]) => { - const combinedOptions: google.maps.MapOptions = { - ...options, - // It's important that we set **some** kind of `center` and `zoom`, otherwise - // Google Maps will render a blank rectangle which looks broken. - center: center || options.center || DEFAULT_OPTIONS.center, - zoom: zoom ?? options.zoom ?? DEFAULT_OPTIONS.zoom, - mapTypeId: this.mapTypeId - }; - return combinedOptions; - })); - } - - private _initializeMap(optionsChanges: Observable): - Observable { - return optionsChanges.pipe( - take(1), - 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)); - } - - private _watchForOptionsChanges() { - combineLatest([this._googleMapChanges, this._options]) - .pipe(takeUntil(this._destroy)) - .subscribe(([googleMap, options]) => { - googleMap.setOptions(options); - }); - } - - private _watchForCenterChanges() { - combineLatest([this._googleMapChanges, this._center]) - .pipe(takeUntil(this._destroy)) - .subscribe(([googleMap, center]) => { - if (center) { - googleMap.setCenter(center); - } - }); - } - - private _watchForZoomChanges() { - combineLatest([this._googleMapChanges, this._zoom]) - .pipe(takeUntil(this._destroy)) - .subscribe(([googleMap, zoom]) => { - if (zoom !== undefined) { - googleMap.setZoom(zoom); - } - }); + private _combineOptions(): google.maps.MapOptions { + const options = this._options; + return { + ...options, + // It's important that we set **some** kind of `center` and `zoom`, otherwise + // Google Maps will render a blank rectangle which looks broken. + center: this._center || options.center || DEFAULT_OPTIONS.center, + zoom: this._zoom ?? options.zoom ?? DEFAULT_OPTIONS.zoom, + mapTypeId: this.mapTypeId + }; } /** Asserts that the map has been initialized. */ diff --git a/tools/public_api_guard/google-maps/google-maps.d.ts b/tools/public_api_guard/google-maps/google-maps.d.ts index cd94f645f9f6..f6d4143d2611 100644 --- a/tools/public_api_guard/google-maps/google-maps.d.ts +++ b/tools/public_api_guard/google-maps/google-maps.d.ts @@ -40,7 +40,7 @@ export declare class GoogleMap implements OnChanges, OnInit, OnDestroy { getStreetView(): google.maps.StreetViewPanorama; getTilt(): number; getZoom(): number; - ngOnChanges(): void; + ngOnChanges(changes: SimpleChanges): void; ngOnDestroy(): void; ngOnInit(): void; panBy(x: number, y: number): void;