diff --git a/src/dev-app/google-map/google-map-demo.html b/src/dev-app/google-map/google-map-demo.html
index c0b7c03a4d40..68783e384dd4 100644
--- a/src/dev-app/google-map/google-map-demo.html
+++ b/src/dev-app/google-map/google-map-demo.html
@@ -101,4 +101,16 @@
+
+
+
+
diff --git a/src/dev-app/google-map/google-map-demo.ts b/src/dev-app/google-map/google-map-demo.ts
index 1e3c234daaf9..faf3adb5752f 100644
--- a/src/dev-app/google-map/google-map-demo.ts
+++ b/src/dev-app/google-map/google-map-demo.ts
@@ -66,7 +66,17 @@ export class GoogleMapDemo {
circleOptions: google.maps.CircleOptions =
{center: CIRCLE_CENTER, radius: CIRCLE_RADIUS, strokeColor: 'grey', strokeOpacity: 0.8};
isGroundOverlayDisplayed = false;
- groundOverlayUrl = 'https://angular.io/assets/images/logos/angular/angular.svg';
+ groundOverlayImages = [
+ {
+ title: 'Red logo',
+ url: 'https://angular.io/assets/images/logos/angular/angular.svg'
+ },
+ {
+ title: 'Black logo',
+ url: 'https://angular.io/assets/images/logos/angular/angular_solidBlack.svg'
+ }
+ ];
+ groundOverlayUrl = this.groundOverlayImages[0].url;
groundOverlayBounds = RECTANGLE_BOUNDS;
mapTypeId: google.maps.MapTypeId;
@@ -149,4 +159,8 @@ export class GoogleMapDemo {
toggleGroundOverlayDisplay() {
this.isGroundOverlayDisplayed = !this.isGroundOverlayDisplayed;
}
+
+ groundOverlayUrlChanged(event: Event) {
+ this.groundOverlayUrl = (event.target as HTMLSelectElement).value;
+ }
}
diff --git a/src/google-maps/map-ground-overlay/map-ground-overlay.spec.ts b/src/google-maps/map-ground-overlay/map-ground-overlay.spec.ts
index db74db3ac8bc..a5659c9b9cc0 100644
--- a/src/google-maps/map-ground-overlay/map-ground-overlay.spec.ts
+++ b/src/google-maps/map-ground-overlay/map-ground-overlay.spec.ts
@@ -57,11 +57,11 @@ describe('MapGroundOverlay', () => {
expect(groundOverlaySpy.setMap).toHaveBeenCalledWith(mapSpy);
});
- it('has an error if required url or bounds are not provided', () => {
+ it('has an error if required bounds are not provided', () => {
expect(() => {
const fixture = TestBed.createComponent(TestApp);
fixture.detectChanges();
- }).toThrow(new Error('An image url is required'));
+ }).toThrow(new Error('Image bounds are required'));
});
it('exposes methods that provide information about the Ground Overlay', () => {
@@ -119,6 +119,32 @@ describe('MapGroundOverlay', () => {
expect(addSpy).toHaveBeenCalledWith('dblclick', jasmine.any(Function));
subscription.unsubscribe();
});
+
+ it('should be able to change the image after init', () => {
+ const groundOverlaySpy = createGroundOverlaySpy(url, bounds, groundOverlayOptions);
+ const groundOverlayConstructorSpy =
+ createGroundOverlayConstructorSpy(groundOverlaySpy).and.callThrough();
+
+ const fixture = TestBed.createComponent(TestApp);
+ fixture.componentInstance.url = url;
+ fixture.componentInstance.bounds = bounds;
+ fixture.componentInstance.clickable = clickable;
+ fixture.componentInstance.opacity = opacity;
+ fixture.detectChanges();
+
+ expect(groundOverlayConstructorSpy).toHaveBeenCalledWith(url, bounds, groundOverlayOptions);
+ expect(groundOverlaySpy.setMap).toHaveBeenCalledWith(mapSpy);
+
+ groundOverlaySpy.setMap.calls.reset();
+ fixture.componentInstance.url = 'foo.png';
+ fixture.detectChanges();
+
+ expect(groundOverlaySpy.set).toHaveBeenCalledWith('url', 'foo.png');
+ expect(groundOverlaySpy.setMap).toHaveBeenCalledTimes(2);
+ expect(groundOverlaySpy.setMap).toHaveBeenCalledWith(null);
+ expect(groundOverlaySpy.setMap).toHaveBeenCalledWith(mapSpy);
+ });
+
});
@Component({
diff --git a/src/google-maps/map-ground-overlay/map-ground-overlay.ts b/src/google-maps/map-ground-overlay/map-ground-overlay.ts
index 2fe4b67c4c97..1933b64117f8 100644
--- a/src/google-maps/map-ground-overlay/map-ground-overlay.ts
+++ b/src/google-maps/map-ground-overlay/map-ground-overlay.ts
@@ -28,6 +28,7 @@ export class MapGroundOverlay implements OnInit, OnDestroy {
private _eventManager = new MapEventManager(this._ngZone);
private readonly _opacity = new BehaviorSubject(1);
+ private readonly _url = new BehaviorSubject('');
private readonly _destroyed = new Subject();
/**
@@ -37,13 +38,19 @@ export class MapGroundOverlay implements OnInit, OnDestroy {
*/
groundOverlay?: google.maps.GroundOverlay;
- @Input() url!: string; // Asserted in ngOnInit.
-
+ /** URL of the image that will be shown in the overlay. */
@Input()
- bounds!: google.maps.LatLngBounds|google.maps.LatLngBoundsLiteral; // Asserted in ngOnInit.
+ set url(url: string) {
+ this._url.next(url);
+ }
- @Input() clickable = false;
+ /** Bounds for the overlay. */
+ @Input() bounds: google.maps.LatLngBounds|google.maps.LatLngBoundsLiteral;
+ /** Whether the overlay is clickable */
+ @Input() clickable: boolean = false;
+
+ /** Opacity of the overlay. */
@Input()
set opacity(opacity: number) {
this._opacity.next(opacity);
@@ -69,9 +76,6 @@ export class MapGroundOverlay implements OnInit, OnDestroy {
constructor(private readonly _map: GoogleMap, private readonly _ngZone: NgZone) {}
ngOnInit() {
- if (!this.url) {
- throw Error('An image url is required');
- }
if (!this.bounds) {
throw Error('Image bounds are required');
}
@@ -81,7 +85,8 @@ export class MapGroundOverlay 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.groundOverlay = new google.maps.GroundOverlay(this.url, this.bounds, options);
+ this.groundOverlay =
+ new google.maps.GroundOverlay(this._url.getValue(), this.bounds, options);
});
this._assertInitialized();
this.groundOverlay.setMap(this._map.googleMap!);
@@ -89,6 +94,7 @@ export class MapGroundOverlay implements OnInit, OnDestroy {
});
this._watchForOpacityChanges();
+ this._watchForUrlChanges();
}
}
@@ -150,6 +156,18 @@ export class MapGroundOverlay implements OnInit, OnDestroy {
});
}
+ private _watchForUrlChanges() {
+ this._url.pipe(takeUntil(this._destroyed)).subscribe(url => {
+ this._assertInitialized();
+ const overlay = this.groundOverlay;
+ overlay.set('url', url);
+
+ // Google Maps only redraws the overlay if we re-set the map.
+ overlay.setMap(null);
+ overlay.setMap(this._map.googleMap!);
+ });
+ }
+
private _assertInitialized(): asserts this is {groundOverlay: google.maps.GroundOverlay} {
if (!this._map.googleMap) {
throw Error(
diff --git a/src/google-maps/testing/fake-google-map-utils.ts b/src/google-maps/testing/fake-google-map-utils.ts
index 0ba94b417ccf..a1f53e176d84 100644
--- a/src/google-maps/testing/fake-google-map-utils.ts
+++ b/src/google-maps/testing/fake-google-map-utils.ts
@@ -241,6 +241,7 @@ export function createCircleConstructorSpy(circleSpy: jasmine.SpyObj {
+ const values: {[key: string]: any} = {url};
const groundOverlaySpy = jasmine.createSpyObj('google.maps.GroundOverlay', [
'addListener',
'getBounds',
@@ -248,8 +249,10 @@ export function createGroundOverlaySpy(
'getUrl',
'setMap',
'setOpacity',
+ 'set',
]);
groundOverlaySpy.addListener.and.returnValue({remove: () => {}});
+ groundOverlaySpy.set.and.callFake((key: string, value: any) => values[key] = value);
return groundOverlaySpy;
}
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 3420cbc11d95..a7953b537b0b 100644
--- a/tools/public_api_guard/google-maps/google-maps.d.ts
+++ b/tools/public_api_guard/google-maps/google-maps.d.ts
@@ -94,7 +94,7 @@ export declare class MapGroundOverlay implements OnInit, OnDestroy {
mapClick: Observable;
mapDblclick: Observable;
set opacity(opacity: number);
- url: string;
+ set url(url: string);
constructor(_map: GoogleMap, _ngZone: NgZone);
getBounds(): google.maps.LatLngBounds;
getOpacity(): number;