Skip to content

Commit 71ce50b

Browse files
author
Andrea Barbasso
committed
[UXP-206] refactor open-street-map component to apply DRY
1 parent 0b132a6 commit 71ce50b

3 files changed

Lines changed: 52 additions & 102 deletions

File tree

src/app/core/services/location.service.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ describe('LocationService', () => {
3232
expect(service.isDecimalCoordinateString('45,45,45')).toBeFalse(); // invalid pattern, wrong array size
3333
expect(service.isDecimalCoordinateString('.0,.0')).toBeFalse(); // valid numbers, but invalid pattern
3434
expect(service.isDecimalCoordinateString('45.000,45.000')).toBeTrue();
35-
expect(service.isDecimalCoordinateString('45.000, 45.000')).toBeFalse(); // it contains a space
35+
expect(service.isDecimalCoordinateString('45.000, 45.000')).toBeTrue(); // it contains a space but it can be trimmed
3636
expect(service.isDecimalCoordinateString('200,200')).toBeTrue(); // invalid numbers, but valid pattern
3737
});
3838

src/app/shared/open-street-map/open-street-map.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
[leafletLayers]="leafletLayers">
88
</div>
99
<div *ngIf="showDisplayName" class="my-1 text-muted">{{ displayName$ | async }}</div>
10-
<div *ngIf="(invalidLocationErrorCode | async) as errorCode"
10+
<div *ngIf="((coordinates$ | async) === null) && (invalidLocationErrorCode | async) as errorCode"
1111
class="text-danger">{{ 'location.error.' + errorCode | translate }}
1212
</div>
Lines changed: 50 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
import { Component, ElementRef, Input, OnInit } from '@angular/core';
2-
import {
3-
LocationDDCoordinates,
4-
LocationErrorCodes,
5-
LocationPlace,
6-
LocationService
7-
} from '../../core/services/location.service';
8-
import { filter, map, tap } from 'rxjs/operators';
2+
import { LocationService, LocationDDCoordinates, LocationPlace, LocationErrorCodes } from '../../core/services/location.service';
93
import { BehaviorSubject, Observable } from 'rxjs';
4+
import { filter, map, tap } from 'rxjs/operators';
105
import { TranslateService } from '@ngx-translate/core';
116
import { isNotEmpty } from '../empty.util';
12-
import { icon, latLng, LatLng, Layer, MapOptions, marker, tileLayer } from 'leaflet';
7+
import { icon, LatLng, latLng, Layer, MapOptions, marker, tileLayer } from 'leaflet';
138

149
@Component({
1510
selector: 'ds-open-street-map',
@@ -66,7 +61,7 @@ export class OpenStreetMapComponent implements OnInit {
6661
/**
6762
* Contains error codes from the location service
6863
*/
69-
invalidLocationErrorCode: BehaviorSubject<string> = new BehaviorSubject(undefined);
64+
invalidLocationErrorCode = new BehaviorSubject<string>(undefined);
7065

7166
/**
7267
* The place to be shown in the map
@@ -76,7 +71,7 @@ export class OpenStreetMapComponent implements OnInit {
7671
/**
7772
* The styles that are being applied to the map container
7873
*/
79-
mapStyle: {[key: string]: string} = {};
74+
mapStyle: { [key: string]: string } = {};
8075

8176
/**
8277
* The center of the map
@@ -96,11 +91,7 @@ export class OpenStreetMapComponent implements OnInit {
9691
/**
9792
* The options for the map
9893
*/
99-
leafletOptions: MapOptions = {
100-
// attribution is still needed
101-
// attributionControl: false,
102-
zoomControl: this.showControlsZoom
103-
};
94+
leafletOptions: MapOptions = { zoomControl: this.showControlsZoom };
10495

10596
constructor(
10697
protected translateService: TranslateService,
@@ -109,116 +100,75 @@ export class OpenStreetMapComponent implements OnInit {
109100
}
110101

111102
ngOnInit(): void {
112-
113103
this.mapStyle = {
114104
width: this.width || '100%',
115105
height: this.height || `${(+this.width || this.elementRef.nativeElement.parentElement.offsetWidth) / 2}px`
116106
};
117107

118108
this.coordinates$ = this.place.asObservable().pipe(
119-
filter((place) => isNotEmpty(place)),
120-
map((place) => place.coordinates),
109+
filter(isNotEmpty),
110+
map(place => place.coordinates),
121111
tap(coordinates => this.setCenterAndPointer(coordinates))
122112
);
123113

124114
this.displayName$ = this.place.asObservable().pipe(
125-
filter((place) => isNotEmpty(place)),
126-
map((place) => place.displayName),
115+
filter(isNotEmpty),
116+
map(place => place.displayName)
127117
);
128118

129-
const position = this.coordinates; // this may contain a pair or coordinates, a POI, or an address
119+
const position = this.coordinates;
130120

131121
if (this.locationService.isDecimalCoordinateString(position)) {
132-
133-
// Validate the coordinates, then retrieve the location name
134-
135-
if (this.locationService.isValidCoordinateString(position)) {
136-
const coordinates = this.locationService.parseCoordinates(position);
137-
this.locationService.searchByCoordinates(coordinates).subscribe({
138-
next: (displayName) => {
139-
const place: LocationPlace = {
140-
coordinates: coordinates,
141-
displayName: displayName, // Show the name retrieved from Nominatim
142-
};
143-
this.place.next(place);
144-
},
145-
error: (err) => {
146-
// show the map centered on provided coordinates despite the possibility to retrieve a description for the place
147-
const place: LocationPlace = {
148-
coordinates: coordinates,
149-
};
150-
this.place.next(place);
151-
if (err.message === LocationErrorCodes.API_ERROR) {
152-
console.error(err.message);
153-
} else {
154-
console.warn(err.message);
155-
}
156-
},
157-
});
158-
} else {
159-
console.error(`Invalid coordinates: "${position}"`);
160-
this.invalidLocationErrorCode.next(LocationErrorCodes.INVALID_COORDINATES);
161-
}
162-
122+
this.handleDecimalCoordinates(position);
163123
} else if (this.locationService.isSexagesimalCoordinateString(position)) {
164-
165-
// Retrieve the decimal coordinates and the place name for the provided coordinates
166-
167-
this.locationService.findPlaceAndDecimalCoordinates(position).subscribe({
168-
next: (place) => {
169-
this.place.next(place);
170-
},
171-
error: (err) => {
172-
this.invalidLocationErrorCode.next(err.message); // either INVALID_COORDINATES or API_ERROR
173-
// show the map centered on provided coordinates despite the possibility to retrieve a description for the place
174-
const coordinates = this.locationService.parseCoordinates(position);
175-
const place: LocationPlace = {
176-
coordinates: coordinates,
177-
};
178-
this.place.next(place);
179-
if (err.message === LocationErrorCodes.API_ERROR) {
180-
console.error(err.message);
181-
} else {
182-
console.warn(err.message);
183-
}
184-
},
185-
});
186-
124+
this.handleSexagesimalCoordinates(position);
187125
} else {
126+
this.handlePlaceOrAddress(position);
127+
}
128+
}
188129

189-
// Retrieve the coordinates for the provided POI or address
190-
191-
this.locationService.findPlaceCoordinates(position).subscribe({
192-
next: (place) => {
193-
place.displayName = position; // Show the name stored in metadata (comment out to show name retrieved from Nominatim)
194-
this.place.next(place);
195-
},
196-
error: (err) => {
197-
this.invalidLocationErrorCode.next(err.message); // either LOCATION_NOT_FOUND or API_ERROR
198-
// show the map centered on provided coordinates despite the possibility to retrieve a description for the place
199-
const coordinates = this.locationService.parseCoordinates(position);
200-
const place: LocationPlace = {
201-
coordinates: coordinates,
202-
};
203-
this.place.next(place);
204-
if (err.message === LocationErrorCodes.API_ERROR) {
205-
console.error(err.message);
206-
} else {
207-
console.warn(err.message);
208-
}
209-
},
130+
private handleDecimalCoordinates(position: string) {
131+
if (this.locationService.isValidCoordinateString(position)) {
132+
const coordinates = this.locationService.parseCoordinates(position);
133+
this.locationService.searchByCoordinates(coordinates).subscribe({
134+
next: displayName => this.place.next({ coordinates, displayName }),
135+
error: err => this.handleError(err, coordinates)
210136
});
137+
} else {
138+
this.invalidLocationErrorCode.next(LocationErrorCodes.INVALID_COORDINATES);
211139
}
140+
}
141+
142+
private handleSexagesimalCoordinates(position: string) {
143+
this.locationService.findPlaceAndDecimalCoordinates(position).subscribe({
144+
next: place => this.place.next(place),
145+
error: err => this.handleError(err, this.locationService.parseCoordinates(position))
146+
});
147+
}
148+
149+
private handlePlaceOrAddress(position: string) {
150+
this.locationService.findPlaceCoordinates(position).subscribe({
151+
next: place => {
152+
place.displayName = position;
153+
this.place.next(place);
154+
},
155+
error: err => this.handleError(err, this.locationService.parseCoordinates(position))
156+
});
157+
}
212158

159+
private handleError(err: any, coordinates: LocationDDCoordinates) {
160+
this.invalidLocationErrorCode.next(err.message);
161+
this.place.next({ coordinates });
162+
console.error(err.message);
213163
}
214164

215165
private setCenterAndPointer(coordinates: LocationDDCoordinates) {
216166
this.leafletCenter = latLng(+coordinates.latitude, +coordinates.longitude);
217167
this.leafletLayers = [
218-
tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {maxZoom: 18, attribution: 'Leaflet'}),
219-
marker(
220-
[+coordinates.latitude, +coordinates.longitude],
221-
{icon: icon({iconUrl: 'assets/images/marker-icon.png', shadowUrl: 'assets/images/marker-shadow.png'})})
168+
tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18, attribution: 'Leaflet' }),
169+
marker([+coordinates.latitude, +coordinates.longitude], {
170+
icon: icon({ iconUrl: 'assets/images/marker-icon.png', shadowUrl: 'assets/images/marker-shadow.png' })
171+
})
222172
];
223173
}
224174
}

0 commit comments

Comments
 (0)