Creating quick suburbs look up using ASP.NET Core web API and Angular 2 – part 2
In this tutorial I will be building a Australian suburb look up module using ASP.NET Core web API, as the second part I will create the client side, using Angular 2. Check out the part 1 for server side.
Below is the suburb.service.ts
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 { Suburb } from '../models'; import { BaseService } from './base.service'; import { LocalStorageService } from './local.storage.service'; import { HttpClient } from '../http.client'; @Injectable() export class SuburbService extends BaseService { private apiUrl = 'api/Suburbs'; private http; constructor(private httpClient: HttpClient, private storageService: LocalStorageService) { super(); this.http = httpClient; } search(searchTerm: string): Observable<Suburb[]> { return this.http.get(this.apiUrl + "/Search?searchTerm=" + searchTerm) .map(this.extractData) .catch(this.handleError); } }
I will be using the ng2-bootstrap typeahead for this one as it is super simple to integrate.
<div class="form-group" [ngClass]="{'has-error':!form.controls['suburb'].valid}"> <label>Suburb</label> <input formControlName="suburb" autocomplete="off" [attr.maxlength]="75" [typeahead]="suburbs" (typeaheadLoading)="suburbsLoading($event)" (typeaheadOnSelect)="suburbOnSelect($event)" [typeaheadItemTemplate]="suburbItemTemplate" typeaheadOptionField="name" typeaheadWaitMs="300" placeholder="Suburb" class="form-control" autocomplete="off"> <template #suburbItemTemplate let-model="item">{{model.name}} {{model.postCode}} - <strong>{{model.state}}</strong></template> <span class="ng-typeahead-mini-loader" *ngIf="suburbLoading"><i class="fa fa-cog fa-spin"></i></span> </div>
this is how CustomerDetailsComponent.ts looks like which is using the typeahead
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 { SuburbService } from './../services/suburb.service'; import { TypeaheadMatch } from 'ng2-bootstrap/typeahead'; import { Suburb } from './../models'; @Component({ selector: 'customer-details', templateUrl: './details.component.html' }) export class CustomerDetailsComponent implements OnInit { form: FormGroup; errorMessage: string; public suburbs: Observable<Suburb[]>; public suburbsSelected: string; public suburbLoading: boolean; private http; constructor(public fb: FormBuilder, private route: ActivatedRoute, private router: Router, private suburbService: SuburbService) { } ngOnInit() { var id: number; this.form = this.initForm(); this.initSuburbLookup(); .... } initForm() { return this.fb.group({ .... suburb: ['', [Validators.required]], .... }); } initSuburbLookup() { this.suburbs = Observable.create((observer: any) => { this.suburbService.search(this.form.value.suburb) .subscribe((data: any) => { observer.next(data); }); }); } public suburbsLoading(e: boolean): void { this.suburbLoading = e; } public suburbOnSelect(e: TypeaheadMatch): void { this.form.patchValue({ state: e.item.state, postcode: e.item.postCode }); } }