Think of angular service as nothing special but an ES6 class that exports some methods to be consumed by components. First lets clone/download an Angular 2 seed project from Angular’s github repo ( https://github.com/angular/angular2-seed ) and navigate to angular2-seed folder and run npm install. This will install all necessary modules to run the application. Open your project in visual studio code which is a free code editor.
In src folder let’s create a services folder and add a file called countrylist.service.ts. In this file add a class called CountryListService . This is a bare bone class that will provide you with a method to get list of countries so lets add a method to it called getCountries().
class CountryListService { getCountries(){ //This method will return list of countries. } }
For service to be available to other components we have to export the class and add @Injectable() decorator to class to allow Angular to inject objects in it when required. Think of decorates as an annotations used in C# or java. It provide some metadata to angular to function it properly. To use @Injectable you have to import it from '@angular/core'. At this point you have a class that looks like.
import { Injectable } from '@angular/core'; @Injectable() export class CountryListService { getCountries(){ //This method will return list of countries. } }
Now we are ready to write actual implementation of getCountries(). The REST web service we are going to use is ( https://restcountries.eu/rest/v1/all ). It returns a lot of data but we are only interested in name of countries. We need an http object to call this web service so we need to import Http module from '@angular/http’. Now you can declare an http object in the class and create a new instance when required but Angular provides an alternative where you declare a private variable in constructor of the type you need and it will create an instance when you need it. This is done via dependency injection without you needing to create an object explicitly.
import { Injectable } from '@angular/core'; import {Http, Response, Headers, RequestOptions} from '@angular/http'; @Injectable() export class CountryListService { constructor(private http:Http) { } getCountries(){ //This method will return list of countries. We can use http variable from constructor to call get method. } }
Now we implement getCountries() method. We use http.get method which returns an Observable
getCountries():Observable{ //You can provide additional header options to get which is not required here. //let headers = new Headers({'content-type':'application/json'}); //let options = new RequestOptions({headers:headers}); return this.http.get("https://restcountries.eu/rest/v1/all") .map(this.extactData) .catch(this.handleError); } private extactData(resp:Response){ let body = resp.json(); console.log(body); return body ; } private handleError(error:any){ console.log(error); return Observable.throw(error.statusText); }
Now we have fully implemented our service lets make it available to the components. Open app.module.ts and add it to providers array providers: [ CountryListService,... ]. You need to import the service from services folder. This makes Angular aware that whenever any component in AppModule asks for object of type CountryListService where it can create one from. Angular maintains a single instance of this service per module using injector.
import {CountryListService} from './services/countrylist.service' providers: [ CountryListService, GithubService ],
Now that our service is implemented and ready to be used by components in AppModule lets go to home folder and open home.component.ts . Let import our service and observable first. We use the same principal we used in service to inject service instance via private constructor variable and create a variable of type array to hold list of countries.
import {CountryListService} from '../services/countrylist.service' import {Observable } from 'rxjs/Rx' countries:any[]=[]; // declared inside the HomeComponent class constructor(private countryListService : CountryListService){ }
Where should you call the service you just written to populate countries array ? It depends on at what point you need the data. If you need the data when your form loads you can implement OnInit from Angular and override ngOnInit method and call the web service there. So lets do that. You need to import OnInit from @angular/core. At this point class signature will look like export class HomeComponent implements OnInit. getCountries() return an Observable so you have to subscribe to it to get data out of it. Here we are using lambda like syntax to subscribe to response or error. Once data is returned we are logging it to console and populating the array with only name field. Hover over subscribe to understand the syntax properly. If there is an error we are just simply logging it to console. You may want to do more with error later.
ngOnInit() { this.countryListService.getCountries().subscribe( data=>{console.log(data); for (var i=data.length;i--;) { console.log('returned : ' + data[i].name) this.countries[i]=data[i].name; } }, err=> console.log(err) ) }
Now we are ready to display this data in home.component.html. I have added a dropdown for country. We are using *ngFor directive to loop through each country in the array and add it as an option.
<select class="form-control" #country name="country"> <option value="default">Select country...</option> <option *ngFor="let cnt of countries"> {{ cnt }} </option> </select>
Now to run the application from command prompt run npm start and navigate to browser http://localhost:3000/ . You will be able to see list of countries in a dropdown.
You can use Google chrome’s developer tools using F12 to view the console log. That’s it. There are many moving parts but once you understand how it all fits together it becomes easy to implement service. You can extend on this service by implementing OnDestroy and unsubscribe from the Observable.
No comments:
Post a Comment