Skip to content

Commit 5fcf26f

Browse files
committed
refactor(google-maps): Removes reference to GoogleMap from MapMarker
Get access to the GoogleMap parent component from a MapMarker through the constructor instead of calling a "setMap" method on the marker from the GoogleMap to prevent MapMarker being loaded in all maps.
1 parent 8e141ef commit 5fcf26f

File tree

5 files changed

+53
-120
lines changed

5 files changed

+53
-120
lines changed

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

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ 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';
65
import {
76
createMapConstructorSpy,
87
createMapSpy,
@@ -40,7 +39,6 @@ describe('GoogleMap', () => {
4039
TestBed.configureTestingModule({
4140
imports: [
4241
GoogleMapModule,
43-
MapMarkerModule,
4442
],
4543
declarations: [TestApp],
4644
});
@@ -242,18 +240,6 @@ describe('GoogleMap', () => {
242240
expect(mapSpy.addListener).not.toHaveBeenCalledWith('tilt_changed', jasmine.any(Function));
243241
expect(mapSpy.addListener).not.toHaveBeenCalledWith('zoom_changed', jasmine.any(Function));
244242
});
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-
});
257243
});
258244

259245
@Component({
@@ -266,7 +252,6 @@ describe('GoogleMap', () => {
266252
(mapClick)="handleClick($event)"
267253
(centerChanged)="handleCenterChanged()"
268254
(mapRightclick)="handleRightclick($event)">
269-
<map-marker></map-marker>
270255
</google-map>`,
271256
})
272257
class TestApp {

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

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,15 @@
77
*/
88

99
import {
10-
AfterContentInit,
1110
ChangeDetectionStrategy,
1211
Component,
13-
ContentChildren,
1412
ElementRef,
1513
EventEmitter,
1614
Input,
1715
OnChanges,
1816
OnDestroy,
1917
OnInit,
2018
Output,
21-
QueryList,
2219
ViewEncapsulation,
2320
} from '@angular/core';
2421
import {BehaviorSubject, combineLatest, Observable, Subject} from 'rxjs';
@@ -62,7 +59,7 @@ export const DEFAULT_WIDTH = '500px';
6259
template: '<div class="map-container"></div><ng-content></ng-content>',
6360
encapsulation: ViewEncapsulation.None,
6461
})
65-
export class GoogleMap implements OnChanges, OnInit, AfterContentInit, OnDestroy {
62+
export class GoogleMap implements OnChanges, OnInit, OnDestroy {
6663
@Input() height = DEFAULT_HEIGHT;
6764

6865
@Input() width = DEFAULT_WIDTH;
@@ -188,8 +185,6 @@ export class GoogleMap implements OnChanges, OnInit, AfterContentInit, OnDestroy
188185
*/
189186
@Output() zoomChanged = new EventEmitter<void>();
190187

191-
@ContentChildren(MapMarker) _markers: QueryList<MapMarker>;
192-
193188
private _mapEl: HTMLElement;
194189
_googleMap!: UpdatedGoogleMap;
195190

@@ -234,13 +229,6 @@ export class GoogleMap implements OnChanges, OnInit, AfterContentInit, OnDestroy
234229
this._watchForOptionsChanges(combinedOptionsChanges);
235230
}
236231

237-
ngAfterContentInit() {
238-
for (const marker of this._markers.toArray()) {
239-
marker._setMap(this._googleMap);
240-
}
241-
this._watchForMarkerChanges();
242-
}
243-
244232
ngOnDestroy() {
245233
this._destroy.next();
246234
this._destroy.complete();
@@ -472,14 +460,4 @@ export class GoogleMap implements OnChanges, OnInit, AfterContentInit, OnDestroy
472460
}));
473461
}
474462
}
475-
476-
private _watchForMarkerChanges() {
477-
combineLatest(this._googleMapChanges, this._markers.changes)
478-
.pipe(takeUntil(this._destroy))
479-
.subscribe(([googleMap, markers]) => {
480-
for (let marker of markers) {
481-
marker._setMap(googleMap);
482-
}
483-
});
484-
}
485463
}

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

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

5+
import {DEFAULT_OPTIONS, GoogleMapModule, UpdatedGoogleMap} from '../google-map/index';
56
import {
7+
createMapConstructorSpy,
8+
createMapSpy,
69
createMarkerConstructorSpy,
710
createMarkerSpy,
811
TestingWindow
@@ -11,15 +14,23 @@ import {
1114
import {DEFAULT_MARKER_OPTIONS, MapMarker, MapMarkerModule} from './index';
1215

1316
describe('MapMarker', () => {
17+
let mapSpy: jasmine.SpyObj<UpdatedGoogleMap>;
18+
1419
beforeEach(async(() => {
1520
TestBed.configureTestingModule({
16-
imports: [MapMarkerModule],
21+
imports: [
22+
GoogleMapModule,
23+
MapMarkerModule,
24+
],
1725
declarations: [TestApp],
1826
});
1927
}));
2028

2129
beforeEach(() => {
2230
TestBed.compileComponents();
31+
32+
mapSpy = createMapSpy(DEFAULT_OPTIONS);
33+
createMapConstructorSpy(mapSpy).and.callThrough();
2334
});
2435

2536
afterEach(() => {
@@ -32,28 +43,24 @@ describe('MapMarker', () => {
3243
const markerConstructorSpy = createMarkerConstructorSpy(markerSpy).and.callThrough();
3344

3445
const fixture = TestBed.createComponent(TestApp);
35-
const fakeMap = {} as unknown as google.maps.Map;
36-
const markerComponent = fixture.debugElement.query(By.directive(MapMarker)).componentInstance;
37-
markerComponent._setMap(fakeMap);
3846
fixture.detectChanges();
3947

4048
expect(markerConstructorSpy).toHaveBeenCalledWith({
4149
...DEFAULT_MARKER_OPTIONS,
4250
title: undefined,
4351
label: undefined,
4452
clickable: undefined,
45-
map: fakeMap
53+
map: mapSpy,
4654
});
4755
});
4856

4957
it('sets marker inputs', () => {
50-
const fakeMap = {} as unknown as google.maps.Map;
5158
const options: google.maps.MarkerOptions = {
5259
position: {lat: 3, lng: 5},
5360
title: 'marker title',
5461
label: 'marker label',
5562
clickable: false,
56-
map: fakeMap,
63+
map: mapSpy,
5764
};
5865
const markerSpy = createMarkerSpy(options);
5966
const markerConstructorSpy = createMarkerConstructorSpy(markerSpy).and.callThrough();
@@ -63,15 +70,12 @@ describe('MapMarker', () => {
6370
fixture.componentInstance.title = options.title;
6471
fixture.componentInstance.label = options.label;
6572
fixture.componentInstance.clickable = options.clickable;
66-
const markerComponent = fixture.debugElement.query(By.directive(MapMarker)).componentInstance;
67-
markerComponent._setMap(fakeMap);
6873
fixture.detectChanges();
6974

7075
expect(markerConstructorSpy).toHaveBeenCalledWith(options);
7176
});
7277

7378
it('sets marker options, ignoring map', () => {
74-
const fakeMap = {} as unknown as google.maps.Map;
7579
const options: google.maps.MarkerOptions = {
7680
position: {lat: 3, lng: 5},
7781
title: 'marker title',
@@ -84,15 +88,12 @@ describe('MapMarker', () => {
8488

8589
const fixture = TestBed.createComponent(TestApp);
8690
fixture.componentInstance.options = options;
87-
const markerComponent = fixture.debugElement.query(By.directive(MapMarker)).componentInstance;
88-
markerComponent._setMap(fakeMap);
8991
fixture.detectChanges();
9092

91-
expect(markerConstructorSpy).toHaveBeenCalledWith({...options, map: fakeMap});
93+
expect(markerConstructorSpy).toHaveBeenCalledWith({...options, map: mapSpy});
9294
});
9395

9496
it('gives precedence to specific inputs over options', () => {
95-
const fakeMap = {} as unknown as google.maps.Map;
9697
const options: google.maps.MarkerOptions = {
9798
position: {lat: 3, lng: 5},
9899
title: 'marker title',
@@ -106,7 +107,7 @@ describe('MapMarker', () => {
106107
label: 'updated label',
107108
clickable: true,
108109
icon: 'icon name',
109-
map: fakeMap,
110+
map: mapSpy,
110111
};
111112
const markerSpy = createMarkerSpy(options);
112113
const markerConstructorSpy = createMarkerConstructorSpy(markerSpy).and.callThrough();
@@ -117,43 +118,17 @@ describe('MapMarker', () => {
117118
fixture.componentInstance.label = expectedOptions.label;
118119
fixture.componentInstance.clickable = expectedOptions.clickable;
119120
fixture.componentInstance.options = options;
120-
const markerComponent = fixture.debugElement.query(By.directive(MapMarker)).componentInstance;
121-
markerComponent._setMap(fakeMap);
122121
fixture.detectChanges();
123122

124123
expect(markerConstructorSpy).toHaveBeenCalledWith(expectedOptions);
125124
});
126125

127-
it('sets the map on the marker only once', () => {
128-
const markerSpy = createMarkerSpy(DEFAULT_MARKER_OPTIONS);
129-
const markerConstructorSpy = createMarkerConstructorSpy(markerSpy).and.callThrough();
130-
131-
const fixture = TestBed.createComponent(TestApp);
132-
const fakeMap = {} as unknown as google.maps.Map;
133-
const fakeMap2 = {testValue: 'test'} as unknown as google.maps.Map;
134-
const markerComponent = fixture.debugElement.query(By.directive(MapMarker)).componentInstance;
135-
markerComponent._setMap(fakeMap);
136-
markerComponent._setMap(fakeMap2);
137-
fixture.detectChanges();
138-
139-
expect(markerConstructorSpy).toHaveBeenCalledWith({
140-
...DEFAULT_MARKER_OPTIONS,
141-
title: undefined,
142-
label: undefined,
143-
clickable: undefined,
144-
map: fakeMap
145-
});
146-
expect(markerSpy.setOptions).not.toHaveBeenCalled();
147-
});
148-
149126
it('exposes methods that provide information about the marker', () => {
150127
const markerSpy = createMarkerSpy(DEFAULT_MARKER_OPTIONS);
151128
createMarkerConstructorSpy(markerSpy).and.callThrough();
152129

153130
const fixture = TestBed.createComponent(TestApp);
154-
const fakeMap = {} as unknown as google.maps.Map;
155131
const markerComponent = fixture.debugElement.query(By.directive(MapMarker)).componentInstance;
156-
markerComponent._setMap(fakeMap);
157132
fixture.detectChanges();
158133

159134
markerSpy.getAnimation.and.returnValue(null);
@@ -198,9 +173,7 @@ describe('MapMarker', () => {
198173
createMarkerConstructorSpy(markerSpy).and.callThrough();
199174

200175
const fixture = TestBed.createComponent(TestApp);
201-
const fakeMap = {} as unknown as google.maps.Map;
202176
const markerComponent = fixture.debugElement.query(By.directive(MapMarker)).componentInstance;
203-
markerComponent._setMap(fakeMap);
204177
fixture.detectChanges();
205178

206179
expect(markerSpy.addListener)
@@ -233,13 +206,16 @@ describe('MapMarker', () => {
233206

234207
@Component({
235208
selector: 'test-app',
236-
template: `<map-marker [title]="title"
237-
[position]="position"
238-
[label]="label"
239-
[clickable]="clickable"
240-
[options]="options"
241-
(mapClick)="handleClick()"
242-
(positionChanged)="handlePositionChanged()"></map-marker>`,
209+
template: `<google-map>
210+
<map-marker [title]="title"
211+
[position]="position"
212+
[label]="label"
213+
[clickable]="clickable"
214+
[options]="options"
215+
(mapClick)="handleClick()"
216+
(positionChanged)="handlePositionChanged()">
217+
</map-marker>
218+
</google-map>`,
243219
})
244220
class TestApp {
245221
title?: string;

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

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ import {
1616
Output,
1717
ViewEncapsulation
1818
} from '@angular/core';
19-
import {BehaviorSubject, combineLatest, Observable, ReplaySubject, Subject} from 'rxjs';
19+
import {BehaviorSubject, combineLatest, Observable, Subject} from 'rxjs';
2020
import {map, takeUntil} from 'rxjs/operators';
2121

22+
import {GoogleMap} from '../google-map/index';
23+
2224
/**
2325
* Default options for the Google Maps marker component. Displays a marker
2426
* at the Googleplex.
@@ -198,30 +200,26 @@ export class MapMarker implements OnInit, OnDestroy {
198200
new BehaviorSubject<string|google.maps.MarkerLabel|undefined>(undefined);
199201
private readonly _clickable = new BehaviorSubject<boolean|undefined>(undefined);
200202

201-
private readonly _map = new ReplaySubject<google.maps.Map>(1);
202-
203203
private readonly _destroy = new Subject<void>();
204204

205205
private readonly _listeners: google.maps.MapsEventListener[] = [];
206206

207-
private _hasMap = false;
208-
209207
_marker?: google.maps.Marker;
210208

209+
constructor(private readonly googleMap: GoogleMap) {}
210+
211211
ngOnInit() {
212212
const combinedOptionsChanges = this._combineOptions();
213213

214-
combineLatest(this._map, combinedOptionsChanges)
215-
.pipe(takeUntil(this._destroy))
216-
.subscribe(([googleMap, options]) => {
217-
if (this._marker) {
218-
this._marker.setOptions(options);
219-
} else {
220-
this._marker = new google.maps.Marker(options);
221-
this._marker.setMap(googleMap);
222-
this._initializeEventHandlers();
223-
}
224-
});
214+
combinedOptionsChanges.pipe(takeUntil(this._destroy)).subscribe(options => {
215+
if (this._marker) {
216+
this._marker.setOptions(options);
217+
} else {
218+
this._marker = new google.maps.Marker(options);
219+
this._marker.setMap(this.googleMap._googleMap);
220+
this._initializeEventHandlers();
221+
}
222+
});
225223
}
226224

227225
ngOnDestroy() {
@@ -235,13 +233,6 @@ export class MapMarker implements OnInit, OnDestroy {
235233
}
236234
}
237235

238-
_setMap(googleMap: google.maps.Map) {
239-
if (!this._hasMap) {
240-
this._map.next(googleMap);
241-
this._hasMap = true;
242-
}
243-
}
244-
245236
/**
246237
* See
247238
* developers.google.com/maps/documentation/javascript/reference/marker#Marker.getAnimation
@@ -339,16 +330,15 @@ export class MapMarker implements OnInit, OnDestroy {
339330
}
340331

341332
private _combineOptions(): Observable<google.maps.MarkerOptions> {
342-
return combineLatest(
343-
this._options, this._title, this._position, this._label, this._clickable, this._map)
344-
.pipe(map(([options, title, position, label, clickable, googleMap]) => {
333+
return combineLatest(this._options, this._title, this._position, this._label, this._clickable)
334+
.pipe(map(([options, title, position, label, clickable]) => {
345335
const combinedOptions: google.maps.MarkerOptions = {
346336
...options,
347337
title: title || options.title,
348338
position: position || options.position,
349339
label: label || options.label,
350340
clickable: clickable !== undefined ? clickable : options.clickable,
351-
map: googleMap || null,
341+
map: this.googleMap._googleMap || null,
352342
};
353343
return combinedOptions;
354344
}));

0 commit comments

Comments
 (0)