Setting up Angular 2 Project to use HTTP

I recently was working on an Angular 2 demo that demonstrate top to bottom application development.  It took me a couple of hours to figure everything our, so I wanted to take a few minutes to document my steps.

First things first, we have to include necessary script files for both Angular 2 and HTTP.  Unlike Angular 1, HTTP functionality is in a separate file, and it took me a bit of time to come to that conclusion.  Given that, this is a full list of scripts we need to include in our host page.  In my case I use MVC 5, so I am adding the scripts to my _Layout.cshtml page.  Of course, you can use plain vanilla HTML page if you would like.  Here is my layout page’s script section.

<script src="~/node_modules/angular2/bundles/angular2-polyfills.min.js"></script> <script src="~/node_modules/systemjs/dist/system.src.js"></script> <script src="~/node_modules/rxjs/bundles/Rx.js"></script> <script src="~/node_modules/angular2/bundles/angular2.dev.js"></script> <script src="~/node_modules/angular2/bundles/http.dev.js"></script> <script src="~/node_modules/jquery/jquery.min.js"></script> <script src="~/node_modules/bootstrap/bootstrap.min.js"></script>

 

 

In all my Java script applications I inject some server side configuration into the layout page, then move it into an Angular service.  In Angular 2 such services are called injectable, but ultimately they are services, helper classes with a purpose.  I start by adding relevant data to a JavaScript object attached to a window object.

<script> (function (myAngularApp) { (function (config) { config.rootUrl = '@Url.Content("~/")'; console.log("added configuration. Config data is " + JSON.stringify(window.myAngularApp.config)); })(window.myAngularApp.config || (window.myAngularApp.config = {})) })(window.myAngularApp || (window.myAngularApp = {})) </script>

What happens here, is that I will finally move my root application URL into window.myAngularApp.confit.rootUrl location.  Now, I can add an injectable that I will be able to use anywhere.  it is quite simple, not much to look at.

import {Injectable} from 'angular2/core'; @Injectable() export class Configuration { config: IConfig; constructor() { this.config = (<any>window).myAngularApp.config; } } export interface IConfig { rootUrl: string; }

I need to have it available in all parts of the application, so I am adding configuration provider to the application bootstrapping code.

import {Main} from "./Main"; import {bootstrap} from 'angular2/platform/browser'; import { Configuration } from './configuration'; import {HTTP_PROVIDERS} from 'angular2/http'; bootstrap(Main, [Configuration, HTTP_PROVIDERS]);

I am also injecting HTTP_PROVIDERS, which is a convenience collection of HTTP related providers.  My entry point is the Main class.  The second parameter to the bootstrap call is the collection of providers that I want available throughout the entire application.

Now I am going to write the actual injectable service I am going to use to get data from the server over HTTP.  This is the part that is using what I have done so far.  Here is how this class looks.

import { Injectable } from 'angular2/core'; import { EventEmitter } from 'angular2/core'; import { Configuration } from '../shell/configuration'; import { HTTP_PROVIDERS, Http } from 'angular2/http'; import IPersonType = App.Models.IPersonType; @Injectable() export class ContactTypeService { contactTypes: EventEmitter<IPersonType[]>; constructor(private _configuration: Configuration, private _http: Http) { this.contactTypes = new EventEmitter<IPersonType[]>(); } getAll(): void { this._http.get(this._configuration.config.rootUrl + "api/persontypes").subscribe( (result) => { this.contactTypes.emit(result.json()); }, (error) => { alert(error.statusText); }); } }

Let’s walk through this class.  We import Injectable decorator first.  Then I am importing EventEmitter because I want to use Observables instead of Promises.  Then I am importing my configuration injectable.  Finally I am importing HTTP_PROVIDIERS and Http class itself.  I am decorating my services with Injectable decorator as well, making it available to dependency injection system of Angular 2.

The class also has a property of type EventEmitter<IPersonType>.  This emitter exposes subscriptions, so any subscriber will be notified when data arrives into this property.  This occurs in my getAll method.  Get method of Http class returns an observable as well, and I subscribe to this observable to be notified when data arrives from the server.  When it does, I retrieve it via json() call, then pump it into my own event emitter.  The error handler is just a placeholder, I would not do alert calls in the production app.

Finally, I can now inject this service into a component to use it.

import {Component, OnInit} from 'angular2/core'; import {ContactTypeListItem} from './contactTypeListItem'; import {ContactTypeService} from './contactTypeService'; @Component({ selector: 'contact-types', template: ` <h1>Contact Types</h1> <ul class="list-group"> <contact-types-item *ngFor="#item of contactTypes" [contactType]="item"> </contact-types-item> </ul> `, directives: [ContactTypeListItem], providers: [ContactTypeService] }) export class ContactTypesList implements OnInit { contactTypes: App.Models.IPersonType[]; constructor(private _contactTypeService: ContactTypeService) { this._contactTypeService.contactTypes.subscribe(this.processData); } processData = (data: App.Models.IPersonType[]) => { this.contactTypes = data; } ngOnInit(): void { this._contactTypeService.getAll(); } }

Let’s look at the code relevant to HTTP.  We are importing our service, ContactTypeService.  We are also adding it to the list of providers in my component.  I am taking this as a dependency in my constructor and storing it in private property called _contactTypeService.  In the constructor I immediately subscribe to the events, which occur when data arrives from the server into the service.  I move the data into property called contactTypes inside processData method.  It is declared in such a format that captures “this” variable, because the events are raised in context of window object.  Finally, I start data fetch in the init method, using OnInit interface which is part of Angular 2 as well.

Enjoy!

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *