diff --git a/package.json b/package.json index 4116939a07f8..c86c274f4021 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@angular/elements": "^9.1.0", "@angular/forms": "^9.1.0", "@angular/platform-browser": "^9.1.0", - "@types/googlemaps": "^3.37.0", + "@types/googlemaps": "^3.39.3", "@types/youtube": "^0.0.38", "@webcomponents/custom-elements": "^1.1.0", "core-js": "^2.6.9", diff --git a/src/google-maps/google-map/google-map.spec.ts b/src/google-maps/google-map/google-map.spec.ts index 1370413852bc..1c63905dbfdb 100644 --- a/src/google-maps/google-map/google-map.spec.ts +++ b/src/google-maps/google-map/google-map.spec.ts @@ -13,7 +13,6 @@ import { DEFAULT_OPTIONS, DEFAULT_WIDTH, GoogleMap, - UpdatedGoogleMap } from './google-map'; /** Represents boundaries of a map to be used in tests. */ @@ -32,7 +31,7 @@ const testPosition: google.maps.LatLngLiteral = { describe('GoogleMap', () => { let mapConstructorSpy: jasmine.Spy; - let mapSpy: jasmine.SpyObj; + let mapSpy: jasmine.SpyObj; beforeEach(async(() => { TestBed.configureTestingModule({ diff --git a/src/google-maps/google-map/google-map.ts b/src/google-maps/google-map/google-map.ts index 26ba8c2da668..fd6c1297bb80 100644 --- a/src/google-maps/google-map/google-map.ts +++ b/src/google-maps/google-map/google-map.ts @@ -33,15 +33,6 @@ interface GoogleMapsWindow extends Window { google?: typeof google; } -// TODO(mbehrlich): Update this to use original map after updating DefinitelyTyped -/** - * Extends the Google Map interface due to the Definitely Typed implementation - * missing "getClickableIcons". - */ -export interface UpdatedGoogleMap extends google.maps.Map { - getClickableIcons: () => boolean; -} - /** default options set to the Googleplex */ export const DEFAULT_OPTIONS: google.maps.MapOptions = { center: {lat: 37.421995, lng: -122.084092}, @@ -74,7 +65,13 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { private readonly _zoom = new BehaviorSubject(undefined); private readonly _destroy = new Subject(); private _mapEl: HTMLElement; - _googleMap: UpdatedGoogleMap; + + /** + * The underlying google.maps.Map object + * + * See developers.google.com/maps/documentation/javascript/reference/map#Map + */ + googleMap?: google.maps.Map; /** Whether we're currently rendering inside a browser. */ _isBrowser: boolean; @@ -257,8 +254,8 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { ngOnChanges() { this._setSize(); - if (this._googleMap && this.mapTypeId) { - this._googleMap.setMapTypeId(this.mapTypeId); + if (this.googleMap && this.mapTypeId) { + this.googleMap.setMapTypeId(this.mapTypeId); } } @@ -269,8 +266,8 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { this._setSize(); this._googleMapChanges = this._initializeMap(this._combineOptions()); this._googleMapChanges.subscribe((googleMap: google.maps.Map) => { - this._googleMap = googleMap as UpdatedGoogleMap; - this._eventManager.setTarget(this._googleMap); + this.googleMap = googleMap; + this._eventManager.setTarget(this.googleMap); }); this._watchForOptionsChanges(); @@ -293,7 +290,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { bounds: google.maps.LatLngBounds|google.maps.LatLngBoundsLiteral, padding?: number|google.maps.Padding) { this._assertInitialized(); - this._googleMap.fitBounds(bounds, padding); + this.googleMap!.fitBounds(bounds, padding); } /** @@ -302,7 +299,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { */ panBy(x: number, y: number) { this._assertInitialized(); - this._googleMap.panBy(x, y); + this.googleMap!.panBy(x, y); } /** @@ -311,7 +308,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { */ panTo(latLng: google.maps.LatLng|google.maps.LatLngLiteral) { this._assertInitialized(); - this._googleMap.panTo(latLng); + this.googleMap!.panTo(latLng); } /** @@ -322,7 +319,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { latLngBounds: google.maps.LatLngBounds|google.maps.LatLngBoundsLiteral, padding?: number|google.maps.Padding) { this._assertInitialized(); - this._googleMap.panToBounds(latLngBounds, padding); + this.googleMap!.panToBounds(latLngBounds, padding); } /** @@ -331,7 +328,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { */ getBounds(): google.maps.LatLngBounds|null { this._assertInitialized(); - return this._googleMap.getBounds() || null; + return this.googleMap!.getBounds() || null; } /** @@ -340,7 +337,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { */ getCenter(): google.maps.LatLng { this._assertInitialized(); - return this._googleMap.getCenter(); + return this.googleMap!.getCenter(); } /** @@ -349,7 +346,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { */ getClickableIcons(): boolean { this._assertInitialized(); - return this._googleMap.getClickableIcons(); + return this.googleMap!.getClickableIcons(); } /** @@ -358,7 +355,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { */ getHeading(): number { this._assertInitialized(); - return this._googleMap.getHeading(); + return this.googleMap!.getHeading(); } /** @@ -367,7 +364,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { */ getMapTypeId(): google.maps.MapTypeId|string { this._assertInitialized(); - return this._googleMap.getMapTypeId(); + return this.googleMap!.getMapTypeId(); } /** @@ -376,7 +373,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { */ getProjection(): google.maps.Projection|null { this._assertInitialized(); - return this._googleMap.getProjection(); + return this.googleMap!.getProjection(); } /** @@ -385,7 +382,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { */ getStreetView(): google.maps.StreetViewPanorama { this._assertInitialized(); - return this._googleMap.getStreetView(); + return this.googleMap!.getStreetView(); } /** @@ -394,7 +391,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { */ getTilt(): number { this._assertInitialized(); - return this._googleMap.getTilt(); + return this.googleMap!.getTilt(); } /** @@ -403,7 +400,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { */ getZoom(): number { this._assertInitialized(); - return this._googleMap.getZoom(); + return this.googleMap!.getZoom(); } /** @@ -412,7 +409,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { */ get controls(): Array> { this._assertInitialized(); - return this._googleMap.controls; + return this.googleMap!.controls; } /** @@ -421,7 +418,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { */ get data(): google.maps.Data { this._assertInitialized(); - return this._googleMap.data; + return this.googleMap!.data; } /** @@ -430,7 +427,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { */ get mapTypes(): google.maps.MapTypeRegistry { this._assertInitialized(); - return this._googleMap.mapTypes; + return this.googleMap!.mapTypes; } /** @@ -439,7 +436,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { */ get overlayMapTypes(): google.maps.MVCArray { this._assertInitialized(); - return this._googleMap.overlayMapTypes; + return this.googleMap!.overlayMapTypes; } private _setSize() { @@ -507,7 +504,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { /** Asserts that the map has been initialized. */ private _assertInitialized() { - if (!this._googleMap) { + if (!this.googleMap) { throw Error('Cannot access Google Map information before the API has been initialized. ' + 'Please wait for the API to load before trying to interact with it.'); } diff --git a/src/google-maps/map-circle/map-circle.spec.ts b/src/google-maps/map-circle/map-circle.spec.ts index 3187f7ce1952..7c0ffb4f1bc4 100644 --- a/src/google-maps/map-circle/map-circle.spec.ts +++ b/src/google-maps/map-circle/map-circle.spec.ts @@ -2,7 +2,7 @@ import {Component, ViewChild} from '@angular/core'; import {async, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; -import {DEFAULT_OPTIONS, UpdatedGoogleMap} from '../google-map/google-map'; +import {DEFAULT_OPTIONS} from '../google-map/google-map'; import {GoogleMapsModule} from '../google-maps-module'; import { createCircleConstructorSpy, @@ -15,7 +15,7 @@ import { import {MapCircle} from './map-circle'; describe('MapCircle', () => { - let mapSpy: jasmine.SpyObj; + let mapSpy: jasmine.SpyObj; let circleCenter: google.maps.LatLngLiteral; let circleRadius: number; let circleOptions: google.maps.CircleOptions; diff --git a/src/google-maps/map-circle/map-circle.ts b/src/google-maps/map-circle/map-circle.ts index 3772aec0204b..4e942aa8cd30 100644 --- a/src/google-maps/map-circle/map-circle.ts +++ b/src/google-maps/map-circle/map-circle.ts @@ -37,7 +37,7 @@ export class MapCircle implements OnInit, OnDestroy { * * @see developers.google.com/maps/documentation/javascript/reference/polygon#Circle */ - circle: google.maps.Circle; // initialized in ngOnInit + circle?: google.maps.Circle; // initialized in ngOnInit @Input() set options(options: google.maps.CircleOptions) { @@ -167,7 +167,8 @@ export class MapCircle implements OnInit, OnDestroy { this._ngZone.runOutsideAngular(() => { this.circle = new google.maps.Circle(options); }); - this.circle.setMap(this._map._googleMap); + this._assertInitialized(); + this.circle!.setMap(this._map.googleMap!); this._eventManager.setTarget(this.circle); }); @@ -181,7 +182,6 @@ export class MapCircle implements OnInit, OnDestroy { this._eventManager.destroy(); this._destroyed.next(); this._destroyed.complete(); - if (this.circle) { this.circle.setMap(null); } @@ -192,7 +192,8 @@ export class MapCircle implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/polygon#Circle.getBounds */ getBounds(): google.maps.LatLngBounds { - return this.circle.getBounds(); + this._assertInitialized(); + return this.circle!.getBounds(); } /** @@ -200,7 +201,8 @@ export class MapCircle implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/polygon#Circle.getCenter */ getCenter(): google.maps.LatLng { - return this.circle.getCenter(); + this._assertInitialized(); + return this.circle!.getCenter(); } /** @@ -208,7 +210,8 @@ export class MapCircle implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/polygon#Circle.getDraggable */ getDraggable(): boolean { - return this.circle.getDraggable(); + this._assertInitialized(); + return this.circle!.getDraggable(); } /** @@ -216,7 +219,8 @@ export class MapCircle implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/polygon#Circle.getEditable */ getEditable(): boolean { - return this.circle.getEditable(); + this._assertInitialized(); + return this.circle!.getEditable(); } /** @@ -224,7 +228,8 @@ export class MapCircle implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/polygon#Circle.getCenter */ getRadius(): number { - return this.circle.getRadius(); + this._assertInitialized(); + return this.circle!.getRadius(); } /** @@ -232,7 +237,8 @@ export class MapCircle implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/polygon#Circle.getVisible */ getVisible(): boolean { - return this.circle.getVisible(); + this._assertInitialized(); + return this.circle!.getVisible(); } private _combineOptions(): Observable { @@ -249,14 +255,16 @@ export class MapCircle implements OnInit, OnDestroy { private _watchForOptionsChanges() { this._options.pipe(takeUntil(this._destroyed)).subscribe(options => { - this.circle.setOptions(options); + this._assertInitialized(); + this.circle!.setOptions(options); }); } private _watchForCenterChanges() { this._center.pipe(takeUntil(this._destroyed)).subscribe(center => { if (center) { - this.circle.setCenter(center); + this._assertInitialized(); + this.circle!.setCenter(center); } }); } @@ -264,8 +272,22 @@ export class MapCircle implements OnInit, OnDestroy { private _watchForRadiusChanges() { this._radius.pipe(takeUntil(this._destroyed)).subscribe(radius => { if (radius !== undefined) { - this.circle.setRadius(radius); + this._assertInitialized(); + this.circle!.setRadius(radius); } }); } + + private _assertInitialized() { + if (!this._map.googleMap) { + throw Error( + 'Cannot access Google Map information before the API has been initialized. ' + + 'Please wait for the API to load before trying to interact with it.'); + } + if (!this.circle) { + throw Error( + 'Cannot interact with a Google Map Circle before it has been ' + + 'initialized. Please wait for the Circle to load before trying to interact with it.'); + } + } } diff --git a/src/google-maps/map-info-window/map-info-window.spec.ts b/src/google-maps/map-info-window/map-info-window.spec.ts index f23a92ee5516..51101345925b 100644 --- a/src/google-maps/map-info-window/map-info-window.spec.ts +++ b/src/google-maps/map-info-window/map-info-window.spec.ts @@ -2,7 +2,7 @@ import {Component, ViewChild} from '@angular/core'; import {async, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; -import {DEFAULT_OPTIONS, UpdatedGoogleMap} from '../google-map/google-map'; +import {DEFAULT_OPTIONS} from '../google-map/google-map'; import {MapMarker} from '../map-marker/map-marker'; import { createInfoWindowConstructorSpy, @@ -16,7 +16,7 @@ import {GoogleMapsModule} from '../google-maps-module'; import {MapInfoWindow} from './map-info-window'; describe('MapInfoWindow', () => { - let mapSpy: jasmine.SpyObj; + let mapSpy: jasmine.SpyObj; beforeEach(async(() => { TestBed.configureTestingModule({ @@ -112,7 +112,7 @@ describe('MapInfoWindow', () => { it('exposes methods that change the configuration of the info window', () => { const fakeMarker = {} as unknown as google.maps.Marker; - const fakeMarkerComponent = {_marker: fakeMarker} as unknown as MapMarker; + const fakeMarkerComponent = {marker: fakeMarker} as unknown as MapMarker; const infoWindowSpy = createInfoWindowSpy({}); createInfoWindowConstructorSpy(infoWindowSpy).and.callThrough(); diff --git a/src/google-maps/map-info-window/map-info-window.ts b/src/google-maps/map-info-window/map-info-window.ts index 9f6abf453bba..732acb752ed8 100644 --- a/src/google-maps/map-info-window/map-info-window.ts +++ b/src/google-maps/map-info-window/map-info-window.ts @@ -13,21 +13,22 @@ import { Directive, ElementRef, Input, + NgZone, OnDestroy, OnInit, Output, - NgZone, } from '@angular/core'; import {BehaviorSubject, combineLatest, Observable, Subject} from 'rxjs'; -import {map, takeUntil} from 'rxjs/operators'; +import {map, take, takeUntil} from 'rxjs/operators'; import {GoogleMap} from '../google-map/google-map'; -import {MapMarker} from '../map-marker/map-marker'; import {MapEventManager} from '../map-event-manager'; +import {MapMarker} from '../map-marker/map-marker'; /** * Angular component that renders a Google Maps info window via the Google Maps JavaScript API. - * @see developers.google.com/maps/documentation/javascript/reference/info-window + * + * See developers.google.com/maps/documentation/javascript/reference/info-window */ @Directive({ selector: 'map-info-window', @@ -39,7 +40,13 @@ export class MapInfoWindow implements OnInit, OnDestroy { private readonly _position = new BehaviorSubject(undefined); private readonly _destroy = new Subject(); - private _infoWindow?: google.maps.InfoWindow; + + /** + * Underlying google.maps.InfoWindow + * + * See developers.google.com/maps/documentation/javascript/reference/info-window#InfoWindow + */ + infoWindow?: google.maps.InfoWindow; @Input() set options(options: google.maps.InfoWindowOptions) { @@ -93,20 +100,21 @@ export class MapInfoWindow implements OnInit, OnDestroy { ngOnInit() { if (this._googleMap._isBrowser) { - this._combineOptions().pipe(takeUntil(this._destroy)).subscribe(options => { - if (this._infoWindow) { - this._infoWindow.setOptions(options); - } else { - // 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); - } + const combinedOptionsChanges = this._combineOptions(); + + combinedOptionsChanges.pipe(take(1)).subscribe(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); }); + + this._watchForOptionsChanges(); + this._watchForPositionChanges(); } } @@ -121,9 +129,8 @@ export class MapInfoWindow implements OnInit, OnDestroy { * See developers.google.com/maps/documentation/javascript/reference/info-window#InfoWindow.close */ close() { - if (this._infoWindow) { - this._infoWindow.close(); - } + this._assertInitialized(); + this.infoWindow!.close(); } /** @@ -131,7 +138,8 @@ export class MapInfoWindow implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/info-window#InfoWindow.getContent */ getContent(): string|Node { - return this._infoWindow ? this._infoWindow.getContent() : ''; + this._assertInitialized(); + return this.infoWindow!.getContent(); } /** @@ -140,7 +148,8 @@ export class MapInfoWindow implements OnInit, OnDestroy { * #InfoWindow.getPosition */ getPosition(): google.maps.LatLng|null { - return this._infoWindow ? this._infoWindow.getPosition() : null; + this._assertInitialized(); + return this.infoWindow!.getPosition(); } /** @@ -148,7 +157,8 @@ export class MapInfoWindow implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/info-window#InfoWindow.getZIndex */ getZIndex(): number { - return this._infoWindow ? this._infoWindow.getZIndex() : -1; + this._assertInitialized(); + return this.infoWindow!.getZIndex(); } /** @@ -156,11 +166,10 @@ export class MapInfoWindow implements OnInit, OnDestroy { * then the position property of the options input is used instead. */ open(anchor?: MapMarker) { - const marker = anchor ? anchor._marker : undefined; - if (this._googleMap._googleMap && this._infoWindow) { - this._elementRef.nativeElement.style.display = ''; - this._infoWindow!.open(this._googleMap._googleMap, marker); - } + this._assertInitialized(); + const marker = anchor ? anchor.marker : undefined; + this._elementRef.nativeElement.style.display = ''; + this.infoWindow!.open(this._googleMap.googleMap, marker); } private _combineOptions(): Observable { @@ -173,4 +182,34 @@ export class MapInfoWindow implements OnInit, OnDestroy { return combinedOptions; })); } + + private _watchForOptionsChanges() { + this._options.pipe(takeUntil(this._destroy)).subscribe(options => { + this._assertInitialized(); + this.infoWindow!.setOptions(options); + }); + } + + private _watchForPositionChanges() { + this._position.pipe(takeUntil(this._destroy)).subscribe(position => { + if (position) { + this._assertInitialized(); + this.infoWindow!.setPosition(position); + } + }); + } + + private _assertInitialized() { + if (!this._googleMap.googleMap) { + throw Error( + 'Cannot access Google Map information before the API has been initialized. ' + + 'Please wait for the API to load before trying to interact with it.'); + } + if (!this.infoWindow) { + throw Error( + 'Cannot interact with a Google Map Info Window before it has been ' + + 'initialized. Please wait for the Info Window to load before trying to interact with ' + + 'it.'); + } + } } diff --git a/src/google-maps/map-marker/map-marker.spec.ts b/src/google-maps/map-marker/map-marker.spec.ts index 4054dc846302..18ebb14cd0fd 100644 --- a/src/google-maps/map-marker/map-marker.spec.ts +++ b/src/google-maps/map-marker/map-marker.spec.ts @@ -2,7 +2,7 @@ import {Component, ViewChild} from '@angular/core'; import {async, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; -import {DEFAULT_OPTIONS, UpdatedGoogleMap} from '../google-map/google-map'; +import {DEFAULT_OPTIONS} from '../google-map/google-map'; import { createMapConstructorSpy, createMapSpy, @@ -15,7 +15,7 @@ import {GoogleMapsModule} from '../google-maps-module'; import {DEFAULT_MARKER_OPTIONS, MapMarker} from './map-marker'; describe('MapMarker', () => { - let mapSpy: jasmine.SpyObj; + let mapSpy: jasmine.SpyObj; beforeEach(async(() => { TestBed.configureTestingModule({ diff --git a/src/google-maps/map-marker/map-marker.ts b/src/google-maps/map-marker/map-marker.ts index 9c4772978627..17ca132ebb7a 100644 --- a/src/google-maps/map-marker/map-marker.ts +++ b/src/google-maps/map-marker/map-marker.ts @@ -35,7 +35,8 @@ export const DEFAULT_MARKER_OPTIONS = { /** * Angular component that renders a Google Maps marker via the Google Maps JavaScript API. - * @see developers.google.com/maps/documentation/javascript/reference/marker + * + * See developers.google.com/maps/documentation/javascript/reference/marker */ @Component({ selector: 'map-marker', @@ -235,7 +236,12 @@ export class MapMarker implements OnInit, OnDestroy { @Output() zindexChanged: Observable = this._eventManager.getLazyEmitter('zindex_changed'); - _marker?: google.maps.Marker; + /** + * The underlying google.maps.Marker object. + * + * See developers.google.com/maps/documentation/javascript/reference/marker#Marker + */ + marker?: google.maps.Marker; constructor( private readonly _googleMap: GoogleMap, @@ -247,9 +253,10 @@ export class MapMarker implements OnInit, OnDestroy { // 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); + this._ngZone.runOutsideAngular(() => this.marker = new google.maps.Marker(options)); + this._assertInitialized(); + this.marker!.setMap(this._googleMap.googleMap!); + this._eventManager.setTarget(this.marker); }); this._watchForOptionsChanges(); @@ -264,8 +271,8 @@ export class MapMarker implements OnInit, OnDestroy { this._destroy.next(); this._destroy.complete(); this._eventManager.destroy(); - if (this._marker) { - this._marker.setMap(null); + if (this.marker) { + this.marker.setMap(null); } } @@ -274,7 +281,8 @@ export class MapMarker implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/marker#Marker.getAnimation */ getAnimation(): google.maps.Animation|null { - return (this._marker && this._marker.getAnimation()) || null; + this._assertInitialized(); + return this.marker!.getAnimation() || null; } /** @@ -282,7 +290,8 @@ export class MapMarker implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/marker#Marker.getClickable */ getClickable(): boolean { - return this._marker ? this._marker.getClickable() : false; + this._assertInitialized(); + return this.marker!.getClickable(); } /** @@ -290,7 +299,8 @@ export class MapMarker implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/marker#Marker.getCursor */ getCursor(): string|null { - return (this._marker && this._marker.getCursor()) || null; + this._assertInitialized(); + return this.marker!.getCursor() || null; } /** @@ -298,7 +308,8 @@ export class MapMarker implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/marker#Marker.getDraggable */ getDraggable(): boolean { - return this._marker ? !!this._marker.getDraggable() : false; + this._assertInitialized(); + return !!this.marker!.getDraggable(); } /** @@ -306,7 +317,8 @@ export class MapMarker implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/marker#Marker.getIcon */ getIcon(): string|google.maps.Icon|google.maps.Symbol|null { - return (this._marker && this._marker.getIcon()) || null; + this._assertInitialized(); + return this.marker!.getIcon() || null; } /** @@ -314,7 +326,8 @@ export class MapMarker implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/marker#Marker.getLabel */ getLabel(): google.maps.MarkerLabel|null { - return (this._marker && this._marker.getLabel()) || null; + this._assertInitialized(); + return this.marker!.getLabel() || null; } /** @@ -322,7 +335,8 @@ export class MapMarker implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/marker#Marker.getOpacity */ getOpacity(): number|null { - return (this._marker && this._marker.getOpacity()) || null; + this._assertInitialized(); + return this.marker!.getOpacity() || null; } /** @@ -330,7 +344,8 @@ export class MapMarker implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/marker#Marker.getPosition */ getPosition(): google.maps.LatLng|null { - return (this._marker && this._marker.getPosition()) || null; + this._assertInitialized(); + return this.marker!.getPosition() || null; } /** @@ -338,7 +353,8 @@ export class MapMarker implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/marker#Marker.getShape */ getShape(): google.maps.MarkerShape|null { - return (this._marker && this._marker.getShape()) || null; + this._assertInitialized(); + return this.marker!.getShape() || null; } /** @@ -346,7 +362,8 @@ export class MapMarker implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/marker#Marker.getTitle */ getTitle(): string|null { - return (this._marker && this._marker.getTitle()) || null; + this._assertInitialized(); + return this.marker!.getTitle() || null; } /** @@ -354,7 +371,8 @@ export class MapMarker implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/marker#Marker.getVisible */ getVisible(): boolean { - return this._marker ? this._marker.getVisible() : false; + this._assertInitialized(); + return this.marker!.getVisible(); } /** @@ -362,7 +380,8 @@ export class MapMarker implements OnInit, OnDestroy { * developers.google.com/maps/documentation/javascript/reference/marker#Marker.getZIndex */ getZIndex(): number|null { - return (this._marker && this._marker.getZIndex()) || null; + this._assertInitialized(); + return this.marker!.getZIndex() || null; } private _combineOptions(): Observable { @@ -374,7 +393,7 @@ export class MapMarker implements OnInit, OnDestroy { position: position || options.position, label: label || options.label, clickable: clickable !== undefined ? clickable : options.clickable, - map: this._googleMap._googleMap || null, + map: this._googleMap.googleMap, }; return combinedOptions; })); @@ -382,41 +401,59 @@ export class MapMarker implements OnInit, OnDestroy { private _watchForOptionsChanges() { this._options.pipe(takeUntil(this._destroy)).subscribe(options => { - if (this._marker) { - this._marker.setOptions(options); + if (this.marker) { + this._assertInitialized(); + this.marker.setOptions(options); } }); } private _watchForTitleChanges() { this._title.pipe(takeUntil(this._destroy)).subscribe(title => { - if (this._marker && title !== undefined) { - this._marker.setTitle(title); + if (this.marker && title !== undefined) { + this._assertInitialized(); + this.marker.setTitle(title); } }); } private _watchForPositionChanges() { this._position.pipe(takeUntil(this._destroy)).subscribe(position => { - if (this._marker && position) { - this._marker.setPosition(position); + if (this.marker && position) { + this._assertInitialized(); + this.marker.setPosition(position); } }); } private _watchForLabelChanges() { this._label.pipe(takeUntil(this._destroy)).subscribe(label => { - if (this._marker && label !== undefined) { - this._marker.setLabel(label); + if (this.marker && label !== undefined) { + this._assertInitialized(); + this.marker.setLabel(label); } }); } private _watchForClickableChanges() { this._clickable.pipe(takeUntil(this._destroy)).subscribe(clickable => { - if (this._marker && clickable !== undefined) { - this._marker.setClickable(clickable); + if (this.marker && clickable !== undefined) { + this._assertInitialized(); + this.marker.setClickable(clickable); } }); } + + private _assertInitialized() { + if (!this._googleMap.googleMap) { + throw Error( + 'Cannot access Google Map information before the API has been initialized. ' + + 'Please wait for the API to load before trying to interact with it.'); + } + if (!this.marker) { + throw Error( + 'Cannot interact with a Google Map Marker before it has been ' + + 'initialized. Please wait for the Marker to load before trying to interact with it.'); + } + } } diff --git a/src/google-maps/map-polygon/map-polygon.spec.ts b/src/google-maps/map-polygon/map-polygon.spec.ts index fe2f703bfb56..15526ff470ec 100644 --- a/src/google-maps/map-polygon/map-polygon.spec.ts +++ b/src/google-maps/map-polygon/map-polygon.spec.ts @@ -2,7 +2,7 @@ import {Component, ViewChild} from '@angular/core'; import {async, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; -import {DEFAULT_OPTIONS, UpdatedGoogleMap} from '../google-map/google-map'; +import {DEFAULT_OPTIONS} from '../google-map/google-map'; import {GoogleMapsModule} from '../google-maps-module'; import { createMapConstructorSpy, @@ -15,7 +15,7 @@ import { import {MapPolygon} from './map-polygon'; describe('MapPolygon', () => { - let mapSpy: jasmine.SpyObj; + let mapSpy: jasmine.SpyObj; let polygonPath: google.maps.LatLngLiteral[]; let polygonOptions: google.maps.PolygonOptions; diff --git a/src/google-maps/map-polygon/map-polygon.ts b/src/google-maps/map-polygon/map-polygon.ts index 9789d5374bb7..0fe408e27239 100644 --- a/src/google-maps/map-polygon/map-polygon.ts +++ b/src/google-maps/map-polygon/map-polygon.ts @@ -25,7 +25,8 @@ import {MapEventManager} from '../map-event-manager'; /** * Angular component that renders a Google Maps Polygon via the Google Maps JavaScript API. - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polygon + * + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polygon */ @Directive({ selector: 'map-polygon', @@ -40,7 +41,12 @@ export class MapPolygon implements OnInit, OnDestroy { private readonly _destroyed = new Subject(); - _polygon: google.maps.Polygon; // initialized in ngOnInit + /** + * The underlying google.maps.Polygon object. + * + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polygon + */ + polygon?: google.maps.Polygon; @Input() set options(options: google.maps.PolygonOptions) { @@ -55,77 +61,77 @@ export class MapPolygon implements OnInit, OnDestroy { } /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.click + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.click */ @Output() polygonClick: Observable = this._eventManager.getLazyEmitter('click'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.dblclick + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.dblclick */ @Output() polygonDblclick: Observable = this._eventManager.getLazyEmitter('dblclick'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.drag + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.drag */ @Output() polygonDrag: Observable = this._eventManager.getLazyEmitter('drag'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.dragend + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.dragend */ @Output() polygonDragend: Observable = this._eventManager.getLazyEmitter('dragend'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.dragstart + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.dragstart */ @Output() polygonDragstart: Observable = this._eventManager.getLazyEmitter('dragstart'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.mousedown + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.mousedown */ @Output() polygonMousedown: Observable = this._eventManager.getLazyEmitter('mousedown'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.mousemove + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.mousemove */ @Output() polygonMousemove: Observable = this._eventManager.getLazyEmitter('mousemove'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.mouseout + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.mouseout */ @Output() polygonMouseout: Observable = this._eventManager.getLazyEmitter('mouseout'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.mouseover + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.mouseover */ @Output() polygonMouseover: Observable = this._eventManager.getLazyEmitter('mouseover'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.mouseup + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.mouseup */ @Output() polygonMouseup: Observable = this._eventManager.getLazyEmitter('mouseup'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.rightclick + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.rightclick */ @Output() polygonRightclick: Observable = @@ -140,10 +146,11 @@ export class MapPolygon implements OnInit, OnDestroy { // We'll bring it back in inside the `MapEventManager` only for the events that the // user has subscribed to. this._ngZone.runOutsideAngular(() => { - this._polygon = new google.maps.Polygon(options); + this.polygon = new google.maps.Polygon(options); }); - this._polygon.setMap(this._map._googleMap); - this._eventManager.setTarget(this._polygon); + this._assertInitialized(); + this.polygon!.setMap(this._map.googleMap!); + this._eventManager.setTarget(this.polygon); }); this._watchForOptionsChanges(); @@ -155,45 +162,50 @@ export class MapPolygon implements OnInit, OnDestroy { this._eventManager.destroy(); this._destroyed.next(); this._destroyed.complete(); - if (this._polygon) { - this._polygon.setMap(null); + if (this.polygon) { + this.polygon.setMap(null); } } /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.getDraggable */ getDraggable(): boolean { - return this._polygon.getDraggable(); + this._assertInitialized(); + return this.polygon!.getDraggable(); } /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.getEditable + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.getEditable */ getEditable(): boolean { - return this._polygon.getEditable(); + this._assertInitialized(); + return this.polygon!.getEditable(); } /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.getPath + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.getPath */ getPath(): google.maps.MVCArray { - return this._polygon.getPath(); + this._assertInitialized(); + return this.polygon!.getPath(); } /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.getPaths + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.getPaths */ getPaths(): google.maps.MVCArray> { - return this._polygon.getPaths(); + this._assertInitialized(); + return this.polygon!.getPaths(); } /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.getVisible + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polygon.getVisible */ getVisible(): boolean { - return this._polygon.getVisible(); + this._assertInitialized(); + return this.polygon!.getVisible(); } private _combineOptions(): Observable { @@ -208,15 +220,30 @@ export class MapPolygon implements OnInit, OnDestroy { private _watchForOptionsChanges() { this._options.pipe(takeUntil(this._destroyed)).subscribe(options => { - this._polygon.setOptions(options); + this._assertInitialized(); + this.polygon!.setOptions(options); }); } private _watchForPathChanges() { this._paths.pipe(takeUntil(this._destroyed)).subscribe(paths => { if (paths) { - this._polygon.setPaths(paths); + this._assertInitialized(); + this.polygon!.setPaths(paths); } }); } + + private _assertInitialized() { + if (!this._map.googleMap) { + throw Error( + 'Cannot access Google Map information before the API has been initialized. ' + + 'Please wait for the API to load before trying to interact with it.'); + } + if (!this.polygon) { + throw Error( + 'Cannot interact with a Google Map Polygon before it has been ' + + 'initialized. Please wait for the Polygon to load before trying to interact with it.'); + } + } } diff --git a/src/google-maps/map-polyline/map-polyline.spec.ts b/src/google-maps/map-polyline/map-polyline.spec.ts index 7c96a00c106e..e2cc2d57228d 100644 --- a/src/google-maps/map-polyline/map-polyline.spec.ts +++ b/src/google-maps/map-polyline/map-polyline.spec.ts @@ -2,7 +2,7 @@ import {Component, ViewChild} from '@angular/core'; import {async, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; -import {DEFAULT_OPTIONS, UpdatedGoogleMap} from '../google-map/google-map'; +import {DEFAULT_OPTIONS} from '../google-map/google-map'; import {GoogleMapsModule} from '../google-maps-module'; import { createMapConstructorSpy, @@ -15,7 +15,7 @@ import { import {MapPolyline} from './map-polyline'; describe('MapPolyline', () => { - let mapSpy: jasmine.SpyObj; + let mapSpy: jasmine.SpyObj; let polylinePath: google.maps.LatLngLiteral[]; let polylineOptions: google.maps.PolylineOptions; diff --git a/src/google-maps/map-polyline/map-polyline.ts b/src/google-maps/map-polyline/map-polyline.ts index 74fdd180f56b..f1a2594569a7 100644 --- a/src/google-maps/map-polyline/map-polyline.ts +++ b/src/google-maps/map-polyline/map-polyline.ts @@ -25,7 +25,8 @@ import {MapEventManager} from '../map-event-manager'; /** * Angular component that renders a Google Maps Polyline via the Google Maps JavaScript API. - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polyline + * + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polyline */ @Directive({ selector: 'map-polyline', @@ -39,7 +40,12 @@ export class MapPolyline implements OnInit, OnDestroy { private readonly _destroyed = new Subject(); - _polyline?: google.maps.Polyline; // initialized in ngOnInit + /** + * The underlying google.maps.Polyline object. + * + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polyline + */ + polyline?: google.maps.Polyline; @Input() set options(options: google.maps.PolylineOptions) { @@ -53,77 +59,77 @@ export class MapPolyline implements OnInit, OnDestroy { } /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.click + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.click */ @Output() polylineClick: Observable = this._eventManager.getLazyEmitter('click'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.dblclick + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.dblclick */ @Output() polylineDblclick: Observable = this._eventManager.getLazyEmitter('dblclick'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.drag + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.drag */ @Output() polylineDrag: Observable = this._eventManager.getLazyEmitter('drag'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.dragend + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.dragend */ @Output() polylineDragend: Observable = this._eventManager.getLazyEmitter('dragend'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.dragstart + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.dragstart */ @Output() polylineDragstart: Observable = this._eventManager.getLazyEmitter('dragstart'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.mousedown + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.mousedown */ @Output() polylineMousedown: Observable = this._eventManager.getLazyEmitter('mousedown'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.mousemove + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.mousemove */ @Output() polylineMousemove: Observable = this._eventManager.getLazyEmitter('mousemove'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.mouseout + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.mouseout */ @Output() polylineMouseout: Observable = this._eventManager.getLazyEmitter('mouseout'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.mouseover + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.mouseover */ @Output() polylineMouseover: Observable = this._eventManager.getLazyEmitter('mouseover'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.mouseup + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.mouseup */ @Output() polylineMouseup: Observable = this._eventManager.getLazyEmitter('mouseup'); /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.rightclick + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.rightclick */ @Output() polylineRightclick: Observable = @@ -139,9 +145,10 @@ export class MapPolyline implements OnInit, OnDestroy { // 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); + this._ngZone.runOutsideAngular(() => this.polyline = new google.maps.Polyline(options)); + this._assertInitialized(); + this.polyline!.setMap(this._map.googleMap!); + this._eventManager.setTarget(this.polyline); }); this._watchForOptionsChanges(); @@ -153,39 +160,43 @@ export class MapPolyline implements OnInit, OnDestroy { this._eventManager.destroy(); this._destroyed.next(); this._destroyed.complete(); - if (this._polyline) { - this._polyline.setMap(null); + if (this.polyline) { + this.polyline.setMap(null); } } /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.getDraggable */ getDraggable(): boolean { - return this._polyline ? this._polyline.getDraggable() : false; + this._assertInitialized(); + return this.polyline!.getDraggable(); } /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.getEditable + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.getEditable */ getEditable(): boolean { - return this._polyline ? this._polyline.getEditable() : false; + this._assertInitialized(); + return this.polyline!.getEditable(); } /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.getPath + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.getPath */ getPath(): google.maps.MVCArray { + this._assertInitialized(); // @breaking-change 11.0.0 Make the return value nullable. - return this._polyline ? this._polyline.getPath() : null!; + return this.polyline!.getPath(); } /** - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.getVisible + * See developers.google.com/maps/documentation/javascript/reference/polygon#Polyline.getVisible */ getVisible(): boolean { - return this._polyline ? this._polyline.getVisible() : false; + this._assertInitialized(); + return this.polyline!.getVisible(); } private _combineOptions(): Observable { @@ -200,17 +211,32 @@ export class MapPolyline implements OnInit, OnDestroy { private _watchForOptionsChanges() { this._options.pipe(takeUntil(this._destroyed)).subscribe(options => { - if (this._polyline) { - this._polyline.setOptions(options); + if (this.polyline) { + this._assertInitialized(); + this.polyline.setOptions(options); } }); } private _watchForPathChanges() { this._path.pipe(takeUntil(this._destroyed)).subscribe(path => { - if (path && this._polyline) { - this._polyline.setPath(path); + if (path && this.polyline) { + this._assertInitialized(); + this.polyline.setPath(path); } }); } + + private _assertInitialized() { + if (!this._map.googleMap) { + throw Error( + 'Cannot access Google Map information before the API has been initialized. ' + + 'Please wait for the API to load before trying to interact with it.'); + } + if (!this.polyline) { + throw Error( + 'Cannot interact with a Google Map Polyline before it has been ' + + 'initialized. Please wait for the Polyline to load before trying to interact with it.'); + } + } } diff --git a/src/google-maps/map-rectangle/map-rectangle.spec.ts b/src/google-maps/map-rectangle/map-rectangle.spec.ts index 63eb1b291b0a..e8e78bd9ec3d 100644 --- a/src/google-maps/map-rectangle/map-rectangle.spec.ts +++ b/src/google-maps/map-rectangle/map-rectangle.spec.ts @@ -2,7 +2,7 @@ import {Component, ViewChild} from '@angular/core'; import {async, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; -import {DEFAULT_OPTIONS, UpdatedGoogleMap} from '../google-map/google-map'; +import {DEFAULT_OPTIONS} from '../google-map/google-map'; import {GoogleMapsModule} from '../google-maps-module'; import { createMapConstructorSpy, @@ -15,7 +15,7 @@ import { import {MapRectangle} from './map-rectangle'; describe('MapRectangle', () => { - let mapSpy: jasmine.SpyObj; + let mapSpy: jasmine.SpyObj; let rectangleBounds: google.maps.LatLngBoundsLiteral; let rectangleOptions: google.maps.RectangleOptions; diff --git a/src/google-maps/map-rectangle/map-rectangle.ts b/src/google-maps/map-rectangle/map-rectangle.ts index e2c7808a0178..32db574a0c08 100644 --- a/src/google-maps/map-rectangle/map-rectangle.ts +++ b/src/google-maps/map-rectangle/map-rectangle.ts @@ -18,7 +18,8 @@ import {MapEventManager} from '../map-event-manager'; /** * Angular component that renders a Google Maps Rectangle via the Google Maps JavaScript API. - * @see developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle + * + * See developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle */ @Directive({ selector: 'map-rectangle', @@ -32,7 +33,12 @@ export class MapRectangle implements OnInit, OnDestroy { private readonly _destroyed = new Subject(); - _rectangle: google.maps.Rectangle; // initialized in ngOnInit + /** + * The underlying google.maps.Rectangle object. + * + * See developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle + */ + rectangle?: google.maps.Rectangle; @Input() set options(options: google.maps.RectangleOptions) { @@ -45,14 +51,14 @@ export class MapRectangle implements OnInit, OnDestroy { } /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle.boundsChanged */ @Output() boundsChanged: Observable = this._eventManager.getLazyEmitter('bounds_changed'); /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle.click */ @Output() @@ -60,7 +66,7 @@ export class MapRectangle implements OnInit, OnDestroy { this._eventManager.getLazyEmitter('click'); /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle.dblclick */ @Output() @@ -68,7 +74,7 @@ export class MapRectangle implements OnInit, OnDestroy { this._eventManager.getLazyEmitter('dblclick'); /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle.drag */ @Output() @@ -76,7 +82,7 @@ export class MapRectangle implements OnInit, OnDestroy { this._eventManager.getLazyEmitter('drag'); /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle.dragend */ @Output() @@ -84,7 +90,7 @@ export class MapRectangle implements OnInit, OnDestroy { this._eventManager.getLazyEmitter('dragend'); /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle.dragstart */ @Output() @@ -92,7 +98,7 @@ export class MapRectangle implements OnInit, OnDestroy { this._eventManager.getLazyEmitter('dragstart'); /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle.mousedown */ @Output() @@ -100,7 +106,7 @@ export class MapRectangle implements OnInit, OnDestroy { this._eventManager.getLazyEmitter('mousedown'); /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle.mousemove */ @Output() @@ -108,7 +114,7 @@ export class MapRectangle implements OnInit, OnDestroy { this._eventManager.getLazyEmitter('mousemove'); /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle.mouseout */ @Output() @@ -116,7 +122,7 @@ export class MapRectangle implements OnInit, OnDestroy { this._eventManager.getLazyEmitter('mouseout'); /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle.mouseover */ @Output() @@ -124,7 +130,7 @@ export class MapRectangle implements OnInit, OnDestroy { this._eventManager.getLazyEmitter('mouseover'); /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle.mouseup */ @Output() @@ -132,7 +138,7 @@ export class MapRectangle implements OnInit, OnDestroy { this._eventManager.getLazyEmitter('mouseup'); /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle.rightclick */ @Output() @@ -148,10 +154,11 @@ export class MapRectangle implements OnInit, OnDestroy { // We'll bring it back in inside the `MapEventManager` only for the events that the // user has subscribed to. this._ngZone.runOutsideAngular(() => { - this._rectangle = new google.maps.Rectangle(options); + this.rectangle = new google.maps.Rectangle(options); }); - this._rectangle.setMap(this._map._googleMap); - this._eventManager.setTarget(this._rectangle); + this._assertInitialized(); + this.rectangle!.setMap(this._map.googleMap!); + this._eventManager.setTarget(this.rectangle); }); this._watchForOptionsChanges(); @@ -163,41 +170,45 @@ export class MapRectangle implements OnInit, OnDestroy { this._eventManager.destroy(); this._destroyed.next(); this._destroyed.complete(); - if (this._rectangle) { - this._rectangle.setMap(null); + if (this.rectangle) { + this.rectangle.setMap(null); } } /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle.getBounds */ getBounds(): google.maps.LatLngBounds { - return this._rectangle.getBounds(); + this._assertInitialized(); + return this.rectangle!.getBounds(); } /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle.getDraggable */ getDraggable(): boolean { - return this._rectangle.getDraggable(); + this._assertInitialized(); + return this.rectangle!.getDraggable(); } /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle.getEditable */ getEditable(): boolean { - return this._rectangle.getEditable(); + this._assertInitialized(); + return this.rectangle!.getEditable(); } /** - * @see + * See * developers.google.com/maps/documentation/javascript/reference/polygon#Rectangle.getVisible */ getVisible(): boolean { - return this._rectangle.getVisible(); + this._assertInitialized(); + return this.rectangle!.getVisible(); } private _combineOptions(): Observable { @@ -212,15 +223,30 @@ export class MapRectangle implements OnInit, OnDestroy { private _watchForOptionsChanges() { this._options.pipe(takeUntil(this._destroyed)).subscribe(options => { - this._rectangle.setOptions(options); + this._assertInitialized(); + this.rectangle!.setOptions(options); }); } private _watchForBoundsChanges() { this._bounds.pipe(takeUntil(this._destroyed)).subscribe(bounds => { if (bounds) { - this._rectangle.setBounds(bounds); + this._assertInitialized(); + this.rectangle!.setBounds(bounds); } }); } + + private _assertInitialized() { + if (!this._map.googleMap) { + throw Error( + 'Cannot access Google Map information before the API has been initialized. ' + + 'Please wait for the API to load before trying to interact with it.'); + } + if (!this.rectangle) { + throw Error( + 'Cannot interact with a Google Map Rectangle before it has been ' + + 'initialized. Please wait for the Rectangle to load before trying to interact with it.'); + } + } } diff --git a/src/google-maps/package.json b/src/google-maps/package.json index a6e044c71ddd..6b5ea66af49c 100644 --- a/src/google-maps/package.json +++ b/src/google-maps/package.json @@ -25,7 +25,7 @@ }, "homepage": "https://github.com/angular/components/tree/master/src/google-maps#readme", "dependencies": { - "@types/googlemaps": "^3.37.0", + "@types/googlemaps": "^3.39.3", "tslib": "0.0.0-TSLIB" }, "peerDependencies": { @@ -33,7 +33,7 @@ "@angular/common": "0.0.0-NG" }, "sideEffects": false, - "publishConfig":{ - "registry":"https://wombat-dressing-room.appspot.com" + "publishConfig": { + "registry": "https://wombat-dressing-room.appspot.com" } } diff --git a/src/google-maps/testing/fake-google-map-utils.ts b/src/google-maps/testing/fake-google-map-utils.ts index b59a498f6f8d..0103a0af2e12 100644 --- a/src/google-maps/testing/fake-google-map-utils.ts +++ b/src/google-maps/testing/fake-google-map-utils.ts @@ -6,8 +6,6 @@ * found in the LICENSE file at https://angular.io/license */ -import {UpdatedGoogleMap} from '../google-map/google-map'; - /** Window interface for testing */ export interface TestingWindow extends Window { google?: { @@ -24,7 +22,7 @@ export interface TestingWindow extends Window { } /** Creates a jasmine.SpyObj for a google.maps.Map. */ -export function createMapSpy(options: google.maps.MapOptions): jasmine.SpyObj { +export function createMapSpy(options: google.maps.MapOptions): jasmine.SpyObj { const mapSpy = jasmine.createSpyObj('google.maps.Map', [ 'setOptions', 'setCenter', 'setZoom', 'setMap', 'addListener', 'fitBounds', 'panBy', 'panTo', 'panToBounds', 'getBounds', 'getCenter', 'getClickableIcons', 'getHeading', 'getMapTypeId', @@ -36,7 +34,7 @@ export function createMapSpy(options: google.maps.MapOptions): jasmine.SpyObj, apiLoaded = true): jasmine.Spy { + mapSpy: jasmine.SpyObj, apiLoaded = true): jasmine.Spy { const mapConstructorSpy = jasmine.createSpy('Map constructor', (_el: Element, _options: google.maps.MapOptions) => { return mapSpy; 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 2a1f356ffd11..2928951f3fac 100644 --- a/tools/public_api_guard/google-maps/google-maps.d.ts +++ b/tools/public_api_guard/google-maps/google-maps.d.ts @@ -1,11 +1,11 @@ export declare class GoogleMap implements OnChanges, OnInit, OnDestroy { - _googleMap: UpdatedGoogleMap; _isBrowser: boolean; boundsChanged: Observable; set center(center: google.maps.LatLngLiteral | google.maps.LatLng); centerChanged: Observable; get controls(): Array>; get data(): google.maps.Data; + googleMap?: google.maps.Map; headingChanged: Observable; height: string | number; idle: Observable; @@ -59,7 +59,7 @@ export declare class GoogleMapsModule { export declare class MapCircle implements OnInit, OnDestroy { set center(center: google.maps.LatLng | google.maps.LatLngLiteral); centerChanged: Observable; - circle: google.maps.Circle; + circle?: google.maps.Circle; circleClick: Observable; circleDblclick: Observable; circleDrag: Observable; @@ -91,6 +91,7 @@ export declare class MapInfoWindow implements OnInit, OnDestroy { closeclick: Observable; contentChanged: Observable; domready: Observable; + infoWindow?: google.maps.InfoWindow; set options(options: google.maps.InfoWindowOptions); set position(position: google.maps.LatLngLiteral | google.maps.LatLng); positionChanged: Observable; @@ -108,7 +109,6 @@ export declare class MapInfoWindow implements OnInit, OnDestroy { } export declare class MapMarker implements OnInit, OnDestroy { - _marker?: google.maps.Marker; animationChanged: Observable; set clickable(clickable: boolean); clickableChanged: Observable; @@ -127,6 +127,7 @@ export declare class MapMarker implements OnInit, OnDestroy { mapMouseover: Observable; mapMouseup: Observable; mapRightclick: Observable; + marker?: google.maps.Marker; set options(options: google.maps.MarkerOptions); set position(position: google.maps.LatLngLiteral | google.maps.LatLng); positionChanged: Observable; @@ -155,9 +156,9 @@ export declare class MapMarker implements OnInit, OnDestroy { } export declare class MapPolygon implements OnInit, OnDestroy { - _polygon: google.maps.Polygon; set options(options: google.maps.PolygonOptions); set paths(paths: google.maps.MVCArray> | google.maps.MVCArray | google.maps.LatLng[] | google.maps.LatLngLiteral[]); + polygon?: google.maps.Polygon; polygonClick: Observable; polygonDblclick: Observable; polygonDrag: Observable; @@ -182,9 +183,9 @@ export declare class MapPolygon implements OnInit, OnDestroy { } export declare class MapPolyline implements OnInit, OnDestroy { - _polyline?: google.maps.Polyline; set options(options: google.maps.PolylineOptions); set path(path: google.maps.MVCArray | google.maps.LatLng[] | google.maps.LatLngLiteral[]); + polyline?: google.maps.Polyline; polylineClick: Observable; polylineDblclick: Observable; polylineDrag: Observable; @@ -208,10 +209,10 @@ export declare class MapPolyline implements OnInit, OnDestroy { } export declare class MapRectangle implements OnInit, OnDestroy { - _rectangle: google.maps.Rectangle; set bounds(bounds: google.maps.LatLngBounds | google.maps.LatLngBoundsLiteral); boundsChanged: Observable; set options(options: google.maps.RectangleOptions); + rectangle?: google.maps.Rectangle; rectangleClick: Observable; rectangleDblclick: Observable; rectangleDrag: Observable; diff --git a/yarn.lock b/yarn.lock index 87199cb1af5a..6103f2efdc7f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1132,10 +1132,10 @@ "@types/minimatch" "*" "@types/node" "*" -"@types/googlemaps@^3.37.0": - version "3.37.0" - resolved "https://registry.yarnpkg.com/@types/googlemaps/-/googlemaps-3.37.0.tgz#85596a2b93ded3850ac83ff575b66c34053c0ac8" - integrity sha512-kUF1DCVJISf6HZQdgROIs98C0MS40AK5KXxyOju5L1aifNXqMkN5siSGErHYxpEMkDcTA/hu6Dr22fZBTt2qRA== +"@types/googlemaps@^3.39.3": + version "3.39.3" + resolved "https://registry.yarnpkg.com/@types/googlemaps/-/googlemaps-3.39.3.tgz#8664e424f335802c8aa46a94676666b0a0f31d97" + integrity sha512-L8O9HAVFZj0TuiS8h5ORthiMsrrhjxTC8XUusp5k47oXCst4VTm+qWKvrAvmYMybZVokbp4Udco1mNwJrTNZPQ== "@types/gulp@*": version "4.0.5"