Skip to content

Commit c8ceae5

Browse files
mbehrlichjelbourn
authored andcommitted
feat(google-maps): add map-marker component (#16964)
* Refactor google-maps module to have a single entry-point, @angular/google-maps, instead of a separate one for every component. * Add GoogleMap and MapMarker components to index for the google maps module.
1 parent 44b8a47 commit c8ceae5

28 files changed

+913
-126
lines changed

packages.bzl

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,6 @@ MATERIAL_SCSS_LIBS = [
8080
for p in MATERIAL_PACKAGES
8181
]
8282

83-
GOOGLE_MAPS_PACKAGES = [
84-
"google-map",
85-
]
86-
87-
GOOGLE_MAPS_TARGETS = ["//src/google-maps"] + ["//src/google-maps/%s" % p for p in GOOGLE_MAPS_PACKAGES]
88-
8983
MATERIAL_EXPERIMENTAL_PACKAGES = [
9084
"mdc-button",
9185
"mdc-card",

src/dev-app/google-map/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ ng_module(
77
srcs = glob(["**/*.ts"]),
88
assets = ["google-map-demo.html"],
99
deps = [
10-
"//src/google-maps/google-map",
10+
"//src/google-maps",
1111
"@npm//@angular/router",
1212
],
1313
)

src/dev-app/google-map/google-map-demo-module.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@
99
import {CommonModule} from '@angular/common';
1010
import {HttpClientJsonpModule, HttpClientModule} from '@angular/common/http';
1111
import {NgModule} from '@angular/core';
12-
import {GoogleMapModule} from '@angular/google-maps/google-map';
12+
import {GoogleMapsModule} from '@angular/google-maps';
1313
import {RouterModule} from '@angular/router';
1414

1515
import {GoogleMapDemo} from './google-map-demo';
1616

1717
@NgModule({
1818
imports: [
1919
CommonModule,
20-
GoogleMapModule,
20+
GoogleMapsModule,
2121
HttpClientJsonpModule,
2222
HttpClientModule,
2323
RouterModule.forChild([{path: '', component: GoogleMapDemo}]),

src/dev-app/google-map/google-map-demo.html

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@
44
[center]="center"
55
[zoom]="zoom"
66
(mapClick)="handleClick($event)"
7-
(mapMousemove)="handleMove($event)"></google-map>
7+
(mapMousemove)="handleMove($event)"
8+
(mapRightclick)="handleRightclick()">
9+
<map-marker></map-marker>
10+
<map-marker *ngFor="let markerPosition of markerPositions"
11+
[position]="markerPosition"
12+
[options]="markerOptions"
13+
(mapClick)="clickMarker($event)"></map-marker>
14+
</google-map>
815

916
<div>Latitude: {{display?.lat}}</div>
1017
<div>Longitude: {{display?.lng}}</div>

src/dev-app/google-map/google-map-demo.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export class GoogleMapDemo {
1919
isReady = false;
2020

2121
center = {lat: 24, lng: 12};
22+
markerOptions = {draggable: false};
23+
markerPositions: google.maps.LatLngLiteral[] = [];
2224
zoom = 4;
2325
display?: google.maps.LatLngLiteral;
2426

@@ -30,10 +32,19 @@ export class GoogleMapDemo {
3032
}
3133

3234
handleClick(event: google.maps.MouseEvent) {
33-
this.center = event.latLng.toJSON();
35+
this.markerPositions.push(event.latLng.toJSON());
3436
}
3537

3638
handleMove(event: google.maps.MouseEvent) {
3739
this.display = event.latLng.toJSON();
3840
}
41+
42+
clickMarker(event: google.maps.MouseEvent) {
43+
console.log(this.markerOptions);
44+
this.markerOptions = {draggable: true};
45+
}
46+
47+
handleRightclick() {
48+
this.markerPositions.pop();
49+
}
3950
}

src/dev-app/system-config.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,6 @@ var MATERIAL_PACKAGES = [
5555
'tree',
5656
];
5757

58-
var GOOGLE_MAPS_PACKAGES = [
59-
'google-map',
60-
];
61-
6258
var MATERIAL_EXPERIMENTAL_PACKAGES = [
6359
'mdc-button',
6460
'mdc-card',
@@ -103,9 +99,7 @@ MATERIAL_EXPERIMENTAL_PACKAGES.forEach(function(pkgName) {
10399
MATERIAL_PACKAGES.forEach(function(pkgName) {
104100
configureEntryPoint('material', pkgName);
105101
});
106-
GOOGLE_MAPS_PACKAGES.forEach(function(pkgName) {
107-
configureEntryPoint('google-maps', pkgName);
108-
});
102+
configureEntryPoint('google-maps');
109103
configureEntryPoint('youtube-player');
110104

111105
/** Configures the specified package and its entry-point. */

src/dev-app/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"@angular/cdk-experimental/*": ["../cdk-experimental/*"],
1515
"@angular/cdk-experimental": ["../cdk-experimental"],
1616
"@angular/material-moment-adapter": ["../material-moment-adapter/public-api.ts"],
17-
"@angular/google-maps/*": ["../google-maps/*"],
17+
"@angular/google-maps": ["../google-maps"],
1818
"@angular/material-examples": ["../../dist/packages/material-examples"]
1919
}
2020
},

src/google-maps/BUILD.bazel

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,34 @@
11
package(default_visibility = ["//visibility:public"])
22

3-
load("//:packages.bzl", "GOOGLE_MAPS_PACKAGES", "GOOGLE_MAPS_TARGETS", "ROLLUP_GLOBALS")
3+
load("//:packages.bzl", "ROLLUP_GLOBALS")
44
load("//tools:defaults.bzl", "ng_module", "ng_package")
55

6-
# Root "@angular/google-maps" entry-point that does not re-export individual entry-points.
76
ng_module(
87
name = "google-maps",
98
srcs = glob(
109
["*.ts"],
1110
exclude = ["**/*.spec.ts"],
1211
),
1312
module_name = "@angular/google-maps",
14-
deps = ["//src/google-maps/%s" % p for p in GOOGLE_MAPS_PACKAGES] + [
13+
deps = [
14+
"//src/google-maps/google-map",
15+
"//src/google-maps/map-marker",
1516
"@npm//@angular/core",
1617
"@npm//@types/googlemaps",
1718
],
1819
)
1920

20-
filegroup(
21-
name = "overviews",
22-
srcs = ["//src/google-maps/%s:overview" % name for name in GOOGLE_MAPS_PACKAGES],
23-
)
24-
2521
# Creates the @angular/google-maps package published to npm
2622
ng_package(
2723
name = "npm_package",
2824
srcs = ["package.json"],
2925
entry_point = ":public-api.ts",
3026
entry_point_name = "google-maps",
3127
globals = ROLLUP_GLOBALS,
32-
deps = GOOGLE_MAPS_TARGETS,
28+
deps = [":google-maps"],
29+
)
30+
31+
filegroup(
32+
name = "source-files",
33+
srcs = glob(["**/*.ts"]),
3334
)

src/google-maps/google-map/BUILD.bazel

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package(default_visibility = ["//visibility:public"])
22

33
load(
44
"//tools:defaults.bzl",
5-
"markdown_to_html",
65
"ng_module",
76
"ng_test_library",
87
"ng_web_test_suite",
@@ -14,8 +13,8 @@ ng_module(
1413
["**/*.ts"],
1514
exclude = ["**/*.spec.ts"],
1615
),
17-
module_name = "@angular/google-maps/google-map",
1816
deps = [
17+
"//src/google-maps/map-marker",
1918
"@npm//@angular/core",
2019
"@npm//@types/googlemaps",
2120
"@npm//rxjs",
@@ -30,7 +29,8 @@ ng_test_library(
3029
),
3130
deps = [
3231
":google-map",
33-
"//src/google-maps/google-map/testing",
32+
"//src/google-maps/map-marker",
33+
"//src/google-maps/testing",
3434
"@npm//@angular/platform-browser",
3535
],
3636
)
@@ -40,11 +40,6 @@ ng_web_test_suite(
4040
deps = [":unit_test_sources"],
4141
)
4242

43-
markdown_to_html(
44-
name = "overview",
45-
srcs = [":google-map.md"],
46-
)
47-
4843
filegroup(
4944
name = "source-files",
5045
srcs = glob(["**/*.ts"]),

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {NgModule} from '@angular/core';
10-
import {GoogleMap} from './google-map';
9+
import {NgModule} from '@angular/core';
1110

12-
@NgModule({
13-
exports: [GoogleMap],
14-
declarations: [GoogleMap],
15-
})
16-
export class GoogleMapModule {}
11+
import {GoogleMap} from './google-map';
12+
13+
@NgModule({
14+
exports: [GoogleMap],
15+
declarations: [GoogleMap],
16+
})
17+
export class GoogleMapModule {
18+
}

src/google-maps/google-map/google-map.md

Whitespace-only changes.

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

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@ import {Component} from '@angular/core';
22
import {async, TestBed} from '@angular/core/testing';
33
import {By} from '@angular/platform-browser';
44

5+
import {MapMarker, MapMarkerModule} from '../map-marker/index';
6+
import {
7+
createMapConstructorSpy,
8+
createMapSpy,
9+
TestingWindow
10+
} from '../testing/fake-google-map-utils';
11+
512
import {
613
DEFAULT_HEIGHT,
714
DEFAULT_OPTIONS,
@@ -10,11 +17,6 @@ import {
1017
GoogleMapModule,
1118
UpdatedGoogleMap
1219
} from './index';
13-
import {
14-
createMapConstructorSpy,
15-
createMapSpy,
16-
TestingWindow
17-
} from './testing/fake-google-map-utils';
1820

1921
/** Represents boundaries of a map to be used in tests. */
2022
const testBounds: google.maps.LatLngBoundsLiteral = {
@@ -36,7 +38,10 @@ describe('GoogleMap', () => {
3638

3739
beforeEach(async(() => {
3840
TestBed.configureTestingModule({
39-
imports: [GoogleMapModule],
41+
imports: [
42+
GoogleMapModule,
43+
MapMarkerModule,
44+
],
4045
declarations: [TestApp],
4146
});
4247
}));
@@ -237,6 +242,18 @@ describe('GoogleMap', () => {
237242
expect(mapSpy.addListener).not.toHaveBeenCalledWith('tilt_changed', jasmine.any(Function));
238243
expect(mapSpy.addListener).not.toHaveBeenCalledWith('zoom_changed', jasmine.any(Function));
239244
});
245+
246+
it('calls setMap on child marker components', () => {
247+
mapSpy = createMapSpy(DEFAULT_OPTIONS);
248+
createMapConstructorSpy(mapSpy).and.callThrough();
249+
250+
const fixture = TestBed.createComponent(TestApp);
251+
const markerComponent = fixture.debugElement.query(By.directive(MapMarker)).componentInstance;
252+
spyOn(markerComponent, '_setMap').and.callThrough();
253+
fixture.detectChanges();
254+
255+
expect(markerComponent._setMap).toHaveBeenCalledWith(mapSpy);
256+
});
240257
});
241258

242259
@Component({
@@ -246,9 +263,11 @@ describe('GoogleMap', () => {
246263
[center]="center"
247264
[zoom]="zoom"
248265
[options]="options"
249-
(mapClick)="handleClick"
250-
(centerChanged)="handleCenterChanged"
251-
(mapRightclick)="handleRightclick"></google-map>`,
266+
(mapClick)="handleClick($event)"
267+
(centerChanged)="handleCenterChanged()"
268+
(mapRightclick)="handleRightclick($event)">
269+
<map-marker></map-marker>
270+
</google-map>`,
252271
})
253272
class TestApp {
254273
height?: string;

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

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
import {
2+
AfterContentInit,
23
ChangeDetectionStrategy,
34
Component,
5+
ContentChildren,
46
ElementRef,
57
EventEmitter,
68
Input,
79
OnChanges,
810
OnDestroy,
911
OnInit,
1012
Output,
13+
QueryList,
1114
} from '@angular/core';
1215
import {BehaviorSubject, combineLatest, Observable, Subject} from 'rxjs';
1316
import {map, shareReplay, take, takeUntil} from 'rxjs/operators';
1417

18+
import {MapMarker} from '../map-marker/index';
19+
1520
interface GoogleMapsWindow extends Window {
1621
google?: typeof google;
1722
}
@@ -44,9 +49,9 @@ export const DEFAULT_WIDTH = '500px';
4449
@Component({
4550
selector: 'google-map',
4651
changeDetection: ChangeDetectionStrategy.OnPush,
47-
template: '<div class="map-container"></div>',
52+
template: '<div class="map-container"></div><ng-content></ng-content>',
4853
})
49-
export class GoogleMap implements OnChanges, OnInit, OnDestroy {
54+
export class GoogleMap implements OnChanges, OnInit, AfterContentInit, OnDestroy {
5055
@Input() height = DEFAULT_HEIGHT;
5156

5257
@Input() width = DEFAULT_WIDTH;
@@ -172,9 +177,13 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy {
172177
*/
173178
@Output() zoomChanged = new EventEmitter<void>();
174179

180+
@ContentChildren(MapMarker) _markers: QueryList<MapMarker>;
181+
175182
private _mapEl: HTMLElement;
176183
private _googleMap!: UpdatedGoogleMap;
177184

185+
private _googleMapChanges!: Observable<google.maps.Map>;
186+
178187
private readonly _listeners: google.maps.MapsEventListener[] = [];
179188

180189
private readonly _options = new BehaviorSubject<google.maps.MapOptions>(DEFAULT_OPTIONS);
@@ -204,13 +213,21 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy {
204213

205214
const combinedOptionsChanges = this._combineOptions();
206215

207-
const googleMapChanges = this._initializeMap(combinedOptionsChanges);
208-
googleMapChanges.subscribe((googleMap: google.maps.Map) => {
216+
this._googleMapChanges = this._initializeMap(combinedOptionsChanges);
217+
this._googleMapChanges.subscribe((googleMap: google.maps.Map) => {
209218
this._googleMap = googleMap as UpdatedGoogleMap;
219+
210220
this._initializeEventHandlers();
211221
});
212222

213-
this._watchForOptionsChanges(googleMapChanges, combinedOptionsChanges);
223+
this._watchForOptionsChanges(combinedOptionsChanges);
224+
}
225+
226+
ngAfterContentInit() {
227+
for (const marker of this._markers.toArray()) {
228+
marker._setMap(this._googleMap);
229+
}
230+
this._watchForMarkerChanges();
214231
}
215232

216233
ngOnDestroy() {
@@ -391,9 +408,8 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy {
391408
}
392409

393410
private _watchForOptionsChanges(
394-
googleMapChanges: Observable<google.maps.Map>,
395411
optionsChanges: Observable<google.maps.MapOptions>) {
396-
combineLatest(googleMapChanges, optionsChanges)
412+
combineLatest(this._googleMapChanges, optionsChanges)
397413
.pipe(takeUntil(this._destroy))
398414
.subscribe(([googleMap, options]) => {
399415
googleMap.setOptions(options);
@@ -445,4 +461,14 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy {
445461
}));
446462
}
447463
}
464+
465+
private _watchForMarkerChanges() {
466+
combineLatest(this._googleMapChanges, this._markers.changes)
467+
.pipe(takeUntil(this._destroy))
468+
.subscribe(([googleMap, markers]) => {
469+
for (let marker of markers) {
470+
marker._setMap(googleMap);
471+
}
472+
});
473+
}
448474
}

0 commit comments

Comments
 (0)