Creating angular 2 service to work with Google Places API Web Service to get address
In the recent projects I have worked on, I had the requirement to create a address auto look up feature. This is a common requirement these days, people prefer to have address auto completion as it easy to make mistakes by typing it manually. In my case I decided to go with Google Places API Web Service. Since I have worked in the past with google web services, I know how easy it is to implement.
I wrote google.places.service.ts service in in my Angular app to call API and return the list of address matching what user have typed.
import { Injectable } from '@angular/core'; import { Http, Response } from '@angular/http'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/catch'; import 'rxjs/add/operator/map'; import 'rxjs/add/observable/of'; import { BaseService } from './base.service'; import { Config } from '../config'; import { GooglePlacesResponce, GooglePlacesAddress } from './../models'; @Injectable() export class GooglePlacesService extends BaseService { private apiUrl = 'https://maps.googleapis.com/maps/api/place/textsearch/json'; constructor(private http: Http) { super(); } search(query: string): Observable<any> { return this.http.get(this.apiUrl + "?query=" + query + "&key=" + Config.GOOGLE_PLACES_API_KEY) .map(this.extractData) .catch(this.handleError); } }
yep, its that easy.
I am using to ng2-bootstap typeahead, in this sample. below is the html
<div class="form-group" [ngClass]="{'has-error':!form.controls['addressLine'].valid}"> <label>Suburb</label> <input formControlName="addressLine" autocomplete="off" [attr.maxlength]="75" [typeahead]="addresses" (typeaheadLoading)="addressesLoading($event)" typeaheadOptionField="formatted_address" typeaheadWaitMs="300" placeholder="Address" class="form-control"> <template #suburbItemTemplate let-model="item">{{model.name}} {{model.postCode}} - <strong>{{model.state}}</strong></template> <span class="ng-typeahead-mini-loader" *ngIf="addressLoading"><i class="fa fa-cog fa-spin"></i></span> </div>
This is how the Angular component code looks like.
import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute, Params } from '@angular/router'; import { AbstractControl, FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { Observable } from 'rxjs/Observable'; import { GooglePlacesService } from './../services/google.places.service'; import { TypeaheadMatch } from 'ng2-bootstrap/typeahead'; @Component({ selector: 'customer-details', templateUrl: './details.component.html' }) export class CustomerDetailsComponent implements OnInit { form: FormGroup; errorMessage: string; public addresses: Observable<Address[]>; public addressSelected: string; public addressLoading: boolean; private http; constructor(public fb: FormBuilder, private route: ActivatedRoute, private router: Router, private googlePlacesService: GooglePlacesService) { } ngOnInit() { this.form = this.initForm(); this.initSuburbLookup(); } initForm() { return this.fb.group({ customerId: [''], ........ addressLine: ['', [Validators.required]], ..... }); } initSuburbLookup() { this.addresses = Observable.create((observer: any) => { this.googlePlacesService.search(this.form.value.suburb) .subscribe((data: any) => { observer.next(data); }); }); } public addressesLoading(e: boolean): void { this.addressLoading = e; } }