Skip to content

Latest commit

 

History

History

step-05

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 

AngularBeer - AngularJS tutorial - Step 05

Enough of building an app with five beers in a hard-coded dataset! Let's fetch a larger dataset from our server using one of Angular's built-in services called HttpModule. We will use Angular's dependency injection (DI) to provide the service to the beerList.component controller.

Data

Our new dataset is now a list of 11 beers stored in JSON format in the beers/beers.json file in your project. This file is available from the server at the URL http://127.0.0.1:8000/beers/beers.json

beers/beers.json:

[
  ...
  {
    "alcohol": 6.8,
    "description": "A reddish-brown abbey ale brewed with dark malts. The secondary fermentation gives a fruity aroma and a unique spicy character with a distinctive aftertaste. Secondary fermentation in the bottle.",
    "id": "AffligemDubbel",
    "img": "beers/img/AffligemDubbel.jpg",
    "name": "Affligem Dubbel"
  },
  ...
]

Controller

We'll use Angular's HttpModule service in our controller to make an HTTP request to your web server to fetch the data in the beers/beers.json file. HttpModule is just one of several built-in modules that handle common operations in web apps. Angular injects these services for you where you need them.

Dependency injection helps to make your web apps both well-structured (e.g., separate components for presentation, data, and control) and loosely coupled (dependencies between components are not resolved by the components themselves, but by the DI subsystem).

HttpModule makes an HTTP GET request to our web server, asking for beers/beers.json (the url is relative to our index.html file). The server responds by providing the data in the JSON file. (The response might just as well have been dynamically generated by a backend server. To the browser and our app they both look the same. For the sake of simplicity we used a JSON file in this tutorial.)

The HttpModule service returns a Promise with a success method. We call this method to handle the asynchronous response and assign the beer data to the scope controlled by this controller, as a model called beers. Notice that Angular detected the JSON response and parsed it for us!

To use a service in Angular, you simply declare the names of the dependencies you need as arguments to the controller's constructor function, as follows:

app/app.module.ts :

import {NgModule} from "@angular/core";
import {BrowserModule} from "@angular/platform-browser";
import {FormsModule} from "@angular/forms";
import { HttpModule, JsonpModule }  from '@angular/http';
import {BeerList} from "./beerlist/beerList.component";
import {FilterArrayPipe} from "./pipes/filter-array-pipe";
import {OrderByPipe} from "./pipes/orderby-pipe";

@NgModule({
    imports: [
        BrowserModule,
        FormsModule,
        JsonpModule,
        HttpModule
    ],
    declarations: [
        BeerList,
        FilterArrayPipe,
        OrderByPipe
    ],
    bootstrap: [BeerList]
})
export class AppModule {
}

app/beers.service.ts :

import {Injectable} from "@angular/core";
import {Http, Response} from "@angular/http";
import "rxjs/add/operator/toPromise";

@Injectable()
export class BeerService {
    // URL to web API
    private beerUrl = 'beers/beers.json';

    constructor(private http: Http) {
    }

    getBeers(): Promise<any[]> {
        return this.http.get(this.beerUrl)
            .toPromise()
            .then(this.extractData)
            .catch(this.handleError);
    }

    private extractData(res: Response) {
        let body = res.json();
        return body || [];
    }

    private handleError(error: any) {
        // In a real world app, we might use a remote logging infrastructure
        // We'd also dig deeper into the error to get a better message
        let errMsg = (error.message) ? error.message : error.status ? `${error.status} - ${error.statusText}` : 'Server error';
        console.error(errMsg); // log to console instead
        return Promise.reject(errMsg);
    }
}

app/beerlist/beerList.component.ts :

import {Component} from '@angular/core';
import {FilterArrayPipe} from '../pipes/filter-array-pipe';
import {OrderByPipe} from '../pipes/orderby-pipe';
import { BeerService } from '../beers.service';

@Component({
 selector: 'beer-list',
 templateUrl: './app/beerlist/beerList.html',
 pipes: [FilterArrayPipe, OrderByPipe],
 providers: [BeerService]
})

export class BeerList {
 orderProp = 'alcohol';
 beers = [];
 mode = 'Promise';

 constructor (private beerService: BeerService) {}

 ngOnInit() { this.getBeers(); }

 getBeers() {
     this.beerService.getBeers()
         .then(
             beers => {this.beers = beers; console.log(beers)},
             error =>  this.errorMessage = <any>error);
 }

}

Angular's dependency injector provides services to your controller when the controller is being constructed. The dependency injector also takes care of creating any transitive dependencies the service may have (services often depend upon other services).

Experiments

At the bottom of app/beerlist/beerList.html, add a <pre>{{beers | json}}</pre> binding to see the list of beers displayed in json format.

At the top of app/beerlist/beerList.html, add a

<div class="alert alert-danger" role="alert" *ngIf="errorMessage">
  <strong>Oh snap!</strong> {{errorMessage}}.
</div>

to display an error message, you can test if by modifying the beerUrl in app/beers.service.ts.

In the BeerList component, pre-process the http response by limiting the number of beers to the first 5 in the list. Use the following code in the getBeers callback:

getBeers() {
    this.beerService.getBeers()
        .then(
            beers => { this.beers = beers.splice(0, 5); },
            error =>  this.errorMessage = <any>error);
}

Summary

Now that you have learned how easy it is to use Angular services (thanks to Angular's dependency injection), go to step 6, where you will add some thumbnail images of beers and some links.