File

projects/maplander/shared/src/lib/directives/search-box/search-box.directive.ts

Implements

AfterViewInit SearchBox

Metadata

Selector [libSearchBox]

Index

Properties
Methods
Outputs

Constructor

constructor(_ref: ElementRef, _ngZone: NgZone, _dialog: DialogService, _agm: MapsAPILoader, _geoCode: AgmGeocoder)
Parameters :
Name Type Optional
_ref ElementRef No
_ngZone NgZone No
_dialog DialogService No
_agm MapsAPILoader No
_geoCode AgmGeocoder No

Outputs

placeChanged
Type : EventEmitter<SearchBoxEvent>
start
Type : EventEmitter<SearchBoxDirective>

Methods

Private bindingElement
bindingElement()
Returns : void
clearInput
clearInput()
Returns : void
Private getAddressComponents
getAddressComponents(components: any[], location: GeoPt)
Parameters :
Name Type Optional
components any[] No
location GeoPt No
Returns : Address
Private getLocationByGPS
getLocationByGPS()
Returns : void
gps
gps()
Returns : void
Private initGoogleMaps
initGoogleMaps()
Returns : void
ngAfterViewInit
ngAfterViewInit()
Returns : void
Private placeChangeCallback
placeChangeCallback()
Returns : void
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
Returns : void
Private showMessageErrorOnUserLocation
showMessageErrorOnUserLocation()
Returns : void

Properties

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;
  }
}

result-matching ""

    No results matching ""