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