Skip to content

Commit 28c36f8

Browse files
authored
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.
1 parent cd3d0e9 commit 28c36f8

File tree

2 files changed

+52
-81
lines changed

2 files changed

+52
-81
lines changed

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

Lines changed: 51 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ import {
2222
Inject,
2323
PLATFORM_ID,
2424
NgZone,
25+
SimpleChanges,
2526
} from '@angular/core';
2627
import {isPlatformBrowser} from '@angular/common';
27-
import {BehaviorSubject, combineLatest, Observable, Subject} from 'rxjs';
28-
import {map, shareReplay, take, takeUntil} from 'rxjs/operators';
28+
import {Observable} from 'rxjs';
2929
import {MapEventManager} from '../map-event-manager';
3030

3131
interface GoogleMapsWindow extends Window {
@@ -57,13 +57,6 @@ export const DEFAULT_WIDTH = '500px';
5757
})
5858
export class GoogleMap implements OnChanges, OnInit, OnDestroy {
5959
private _eventManager: MapEventManager = new MapEventManager(this._ngZone);
60-
private _googleMapChanges: Observable<google.maps.Map>;
61-
62-
private readonly _options = new BehaviorSubject<google.maps.MapOptions>(DEFAULT_OPTIONS);
63-
private readonly _center =
64-
new BehaviorSubject<google.maps.LatLngLiteral|google.maps.LatLng|undefined>(undefined);
65-
private readonly _zoom = new BehaviorSubject<number|undefined>(undefined);
66-
private readonly _destroy = new Subject<void>();
6760
private _mapEl: HTMLElement;
6861

6962
/**
@@ -90,16 +83,21 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy {
9083

9184
@Input()
9285
set center(center: google.maps.LatLngLiteral|google.maps.LatLng) {
93-
this._center.next(center);
86+
this._center = center;
9487
}
88+
private _center: google.maps.LatLngLiteral|google.maps.LatLng;
89+
9590
@Input()
9691
set zoom(zoom: number) {
97-
this._zoom.next(zoom);
92+
this._zoom = zoom;
9893
}
94+
private _zoom: number;
95+
9996
@Input()
10097
set options(options: google.maps.MapOptions) {
101-
this._options.next(options || DEFAULT_OPTIONS);
98+
this._options = options || DEFAULT_OPTIONS;
10299
}
100+
private _options = DEFAULT_OPTIONS;
103101

104102
/**
105103
* See
@@ -246,10 +244,30 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy {
246244
}
247245
}
248246

249-
ngOnChanges() {
250-
this._setSize();
251-
if (this.googleMap && this.mapTypeId) {
252-
this.googleMap.setMapTypeId(this.mapTypeId);
247+
ngOnChanges(changes: SimpleChanges) {
248+
if (changes['height'] || changes['width']) {
249+
this._setSize();
250+
}
251+
252+
const googleMap = this.googleMap;
253+
254+
if (googleMap) {
255+
if (changes['options'] && this._options) {
256+
googleMap.setOptions(this._options);
257+
}
258+
259+
if (changes['center'] && this._center) {
260+
googleMap.setCenter(this._center);
261+
}
262+
263+
// Note that the zoom can be zero.
264+
if (changes['zoom'] && this._zoom != null) {
265+
googleMap.setZoom(this._zoom);
266+
}
267+
268+
if (changes['mapTypeId'] && this.mapTypeId) {
269+
googleMap.setMapTypeId(this.mapTypeId);
270+
}
253271
}
254272
}
255273

@@ -258,22 +276,19 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy {
258276
if (this._isBrowser) {
259277
this._mapEl = this._elementRef.nativeElement.querySelector('.map-container')!;
260278
this._setSize();
261-
this._googleMapChanges = this._initializeMap(this._combineOptions());
262-
this._googleMapChanges.subscribe((googleMap: google.maps.Map) => {
263-
this.googleMap = googleMap;
264-
this._eventManager.setTarget(this.googleMap);
265-
});
266279

267-
this._watchForOptionsChanges();
268-
this._watchForCenterChanges();
269-
this._watchForZoomChanges();
280+
// Create the object outside the zone so its events don't trigger change detection.
281+
// We'll bring it back in inside the `MapEventManager` only for the events that the
282+
// user has subscribed to.
283+
this._ngZone.runOutsideAngular(() => {
284+
this.googleMap = new google.maps.Map(this._mapEl, this._combineOptions());
285+
});
286+
this._eventManager.setTarget(this.googleMap);
270287
}
271288
}
272289

273290
ngOnDestroy() {
274291
this._eventManager.destroy();
275-
this._destroy.next();
276-
this._destroy.complete();
277292
}
278293

279294
/**
@@ -443,60 +458,16 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy {
443458
}
444459

445460
/** Combines the center and zoom and the other map options into a single object */
446-
private _combineOptions(): Observable<google.maps.MapOptions> {
447-
return combineLatest([this._options, this._center, this._zoom])
448-
.pipe(map(([options, center, zoom]) => {
449-
const combinedOptions: google.maps.MapOptions = {
450-
...options,
451-
// It's important that we set **some** kind of `center` and `zoom`, otherwise
452-
// Google Maps will render a blank rectangle which looks broken.
453-
center: center || options.center || DEFAULT_OPTIONS.center,
454-
zoom: zoom ?? options.zoom ?? DEFAULT_OPTIONS.zoom,
455-
mapTypeId: this.mapTypeId
456-
};
457-
return combinedOptions;
458-
}));
459-
}
460-
461-
private _initializeMap(optionsChanges: Observable<google.maps.MapOptions>):
462-
Observable<google.maps.Map> {
463-
return optionsChanges.pipe(
464-
take(1),
465-
map(options => {
466-
// Create the object outside the zone so its events don't trigger change detection.
467-
// We'll bring it back in inside the `MapEventManager` only for the events that the
468-
// user has subscribed to.
469-
return this._ngZone.runOutsideAngular(() => new google.maps.Map(this._mapEl, options));
470-
}),
471-
shareReplay(1));
472-
}
473-
474-
private _watchForOptionsChanges() {
475-
combineLatest([this._googleMapChanges, this._options])
476-
.pipe(takeUntil(this._destroy))
477-
.subscribe(([googleMap, options]) => {
478-
googleMap.setOptions(options);
479-
});
480-
}
481-
482-
private _watchForCenterChanges() {
483-
combineLatest([this._googleMapChanges, this._center])
484-
.pipe(takeUntil(this._destroy))
485-
.subscribe(([googleMap, center]) => {
486-
if (center) {
487-
googleMap.setCenter(center);
488-
}
489-
});
490-
}
491-
492-
private _watchForZoomChanges() {
493-
combineLatest([this._googleMapChanges, this._zoom])
494-
.pipe(takeUntil(this._destroy))
495-
.subscribe(([googleMap, zoom]) => {
496-
if (zoom !== undefined) {
497-
googleMap.setZoom(zoom);
498-
}
499-
});
461+
private _combineOptions(): google.maps.MapOptions {
462+
const options = this._options;
463+
return {
464+
...options,
465+
// It's important that we set **some** kind of `center` and `zoom`, otherwise
466+
// Google Maps will render a blank rectangle which looks broken.
467+
center: this._center || options.center || DEFAULT_OPTIONS.center,
468+
zoom: this._zoom ?? options.zoom ?? DEFAULT_OPTIONS.zoom,
469+
mapTypeId: this.mapTypeId
470+
};
500471
}
501472

502473
/** Asserts that the map has been initialized. */

tools/public_api_guard/google-maps/google-maps.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export declare class GoogleMap implements OnChanges, OnInit, OnDestroy {
4040
getStreetView(): google.maps.StreetViewPanorama;
4141
getTilt(): number;
4242
getZoom(): number;
43-
ngOnChanges(): void;
43+
ngOnChanges(changes: SimpleChanges): void;
4444
ngOnDestroy(): void;
4545
ngOnInit(): void;
4646
panBy(x: number, y: number): void;

0 commit comments

Comments
 (0)