File
Implements
Index
Properties
|
|
Methods
|
|
Outputs
|
|
Outputs
placeChanged
|
Type : EventEmitter<SearchBoxEvent>
|
|
start
|
Type : EventEmitter<SearchBoxDirective>
|
|
Methods
Private
bindingElement
|
bindingElement()
|
|
|
Private
getAddressComponents
|
getAddressComponents(components: any[], location: GeoPt)
|
|
Parameters :
Name |
Type |
Optional |
components |
any[]
|
No
|
location |
GeoPt
|
No
|
Returns : Address
|
Private
getLocationByGPS
|
getLocationByGPS()
|
|
|
Private
initGoogleMaps
|
initGoogleMaps()
|
|
|
ngAfterViewInit
|
ngAfterViewInit()
|
|
|
Private
placeChangeCallback
|
placeChangeCallback()
|
|
|
reverseGeoCode
|
reverseGeoCode(location: GeoPt)
|
|
Parameters :
Name |
Type |
Optional |
location |
GeoPt
|
No
|
Returns : Observable<SearchBoxEvent>
|
setValueInput
|
setValueInput(value: string)
|
|
Parameters :
Name |
Type |
Optional |
value |
string
|
No
|
|
Private
showMessageErrorOnUserLocation
|
showMessageErrorOnUserLocation()
|
|
|
Private
_autoCompleteInstance
|
Type : any
|
|
import {AfterViewInit, Directive, ElementRef, EventEmitter, NgZone, Output} from '@angular/core';
import {AgmGeocoder, MapsAPILoader} from '@agm/core';
import {Observable} from 'rxjs';
import {SearchBox, Address, GeoPt, SearchBoxEvent} from '@maplander/types';
import {map} from 'rxjs/operators';
import {DialogService} from '../../components/dialog/dialog.service';
declare var google: any;
@Directive({
selector: '[libSearchBox]'
})
export class SearchBoxDirective implements AfterViewInit, SearchBox {
@Output() placeChanged: EventEmitter<SearchBoxEvent>;
@Output() start: EventEmitter<SearchBoxDirective>;
private _autoCompleteInstance: any;
constructor(
private _ref: ElementRef,
private _ngZone: NgZone,
private _dialog: DialogService,
private _agm: MapsAPILoader,
private _geoCode: AgmGeocoder
) {
if (this._ref.nativeElement.constructor !== HTMLInputElement) {
throw new Error('appSearchBox directive use only on input element');
} else {
this.placeChanged = new EventEmitter<SearchBoxEvent>();
this.start = new EventEmitter<SearchBoxDirective>();
}
}
ngAfterViewInit(): void {
this.initGoogleMaps();
}
clearInput(): void {
this._ref.nativeElement.value = '';
}
setValueInput(value: string): void {
this._ref.nativeElement.value = value;
}
gps(): void {
this.getLocationByGPS();
}
reverseGeoCode(location: GeoPt): Observable<SearchBoxEvent> {
const latLng = new google.maps.LatLng(location.latitude, location.longitude);
const request = {location: latLng};
return this._geoCode.geocode(request).pipe(map(results => {
return {
address_formatted: results[0].formatted_address,
address: this.getAddressComponents(results[0].address_components, location)
};
}));
}
private initGoogleMaps(): void {
this._agm.load().then(() => {
this.start.emit(this);
this.bindingElement();
});
}
private bindingElement(): void {
this._autoCompleteInstance = new google.maps.places.Autocomplete(this._ref.nativeElement);
this._autoCompleteInstance.addListener('place_changed', this.placeChangeCallback.bind(this));
}
private getLocationByGPS(): void {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
this.reverseGeoCode({latitude: position.coords.latitude, longitude: position.coords.longitude})
.subscribe((response: SearchBoxEvent) => {
this._ngZone.run(() => {
this.placeChanged.emit(response);
});
});
}, () => {
this.showMessageErrorOnUserLocation();
});
}
}
private placeChangeCallback(): void {
this._ngZone.run(() => {
const place = this._autoCompleteInstance.getPlace();
if (!place.geometry) {
return;
}
this.placeChanged.emit({
address: this.getAddressComponents(place.address_components, {
latitude: place.geometry.location.lat(),
longitude: place.geometry.location.lng()
}),
address_formatted: place.formatted_address
});
});
}
private showMessageErrorOnUserLocation(): void {
this._dialog.alert('InformaciĆ³n', 'No pudimos obtener su ubicaciĆ³n exacta');
}
private getAddressComponents(components: any[], location: GeoPt): Address {
const result: Address = new Address();
result.location = location;
/**
* Mexico -> Ciudad de Mexico -> Ciudad de Mexico -> Iztapalapa -> Juan Escutia -> Francisco Leyva
* Country -> (State) 1 Level -> (City) 2 Level -> (Township) 3 Level -> (Colony) 4 Level -> Street
* */
components.forEach((component) => component.types.forEach((type) => {
switch (type) {
case 'country': // Country
result.country = component.long_name;
break;
case 'administrative_area_level_1': // State
result.state = component.long_name;
break;
case 'administrative_area_level_2': // City
case 'locality':
result.city = component.long_name;
break;
case 'administrative_area_level_3': // Township
result.township = component.long_name;
break;
case 'sublocality_level_1': // Colony
result.colony = component.long_name;
break;
case 'route': // Street
case 'street_address':
case 'intersection':
result.street = component.long_name;
break;
case 'street_number':
result.outdoorNumber = component.long_name;
break;
case 'postal_code': // Postal code
result.postalCode = component.long_name;
break;
}
}));
return result;
}
}