How to build an Angular 2 application with routing and services

I wrote this post because of the lack of Angular 2 articles that cover the basics essential for building an application. There are some tutorials available, but almost none of them show how to use services or routing with parameters. Those are in my opinion some of the most important features when writing an actual application. After reading this post you should be able to create an application in Angular 2 that uses routing (with parameters) and a service.

Please note that Angular 2 is still a developer preview. The API is changing rapidly and Angular 2 should not be used in production yet. Nevertheless I think it’s worth diving into.

For this tutorial I used the latest version available, Alpha v35.

The application

We are going to create an application that consists of two pages. Both pages will use the Spotify API (without authentication) to get data.

Github repo

Demo

The architecture of the application will look as follows:

Search an artist page

This page is the landing page. There will be an input element on this page that makes a Spotify call to find the artist based on the user input. A list of matching artists will be displayed that link to the artist detail page.

/search

Artist detail page

This page will show additional information on an artist based on the ID in the route parameter.

/artist/:id

Spotify service

This service will be a wrapper for two spotify calls

The folder structure

index.html
/app
/components
/search
search.ts
            /artist
artist.ts
            app.ts
        /services
spotify.ts
        /utils
fetch.ts
bootstrap.ts
    /typings
/angular2
angular2.d.ts
router.d.ts
/rx
rx.d.ts
/es6-promise
es6-promise.d.ts
_custom.d.ts

Building the application

Download the typings

Before we can start building we need to get the required typings. I recommend using the TypeScript Definition manager. If you don’t have it yet, you can install it using:

npm install tsd -g

Now we can install the typings

tsd install angular2/angular2 angular2/router rx es6-promise

Next we want to create a bundle of the typings that we just installed, so that we don’t need to refer to all four files in each file that we are going to create. In the folder typings, create a file named _custom.d.ts.

Set up the HTML

The app will use 4 external files.

Traceur (runtime)

Traceur is a JavaScript.next-to-JavaScript-of-today compiler that allows you to use features from the future today.

System.js

Universal dynamic module loader — loads ES6 modules, AMD, CommonJS and global scripts in the browser and NodeJS. Works with both Traceur and Babel.

Angular 2 & Angular 2 router

<app></app>

This is where out application will be rendered.

System.config({
baseURL: ‘/app’
});

System.import(‘bootstrap’);

Using System, we first set the base path of the application, next we tell System to include the “bootstrap” file. The bootstrap file will handle the rest (will be explained later).

app/components/app.ts

App.ts will be the core of the application. We will define the routes, and the main template here.

Let’s go through the file step by step

/// <reference path=”../../../typings/_custom.d.ts” />

This is the reference to the typings bundle we created. Next, we import the modules required by this component.

import { Component, View } from ‘angular2/angular2’;
import { RouteConfig, RouterLink, RouterOutlet } from ‘angular2/router’;

I assume you are already familiar with Component and View, if not I recommend you go through the 5 minutes quickstart on the angular.io website.

RouteConfig is used for setting up the routes, similar the angular’s $routeProvider

RouterLink is used in the HTML to link to pages defined in the RouteConfig

RouterOutlet is used to render the result of the current route, similar to angular’s <ng-view>

import { Search } from ‘../components/search/search’;
import { Artist } from ‘../components/artist/artist’;

These are the components that we still need to create for our search and artist page.

@Component({ selector: ‘app’})

This refers to the selector we just defined in our HTML (<app></app>).

@View({
directives: [RouterLink, RouterOutlet],
template: `
<header>
<nav>
<ul>
<li>
<a [router-link]=”[‘/search’]”>Search</a>
</li>
</ul>
</nav>
</header>

<main>
<h1>{{title}}</h1>
<router-outlet></router-outlet>
</main>
`
})

First we tell this component which directives we are going to use inside the template. Next we define the template. You can also use templateUrl instead of template if you prefer to keep your HTML and JS separated.

Notice that we use the directives defined above in our HTML. First we use [router-link] which will create a link to the corresponding template. In the <main> section we use <router-outlet> which will be used as output for angular’s router.

@RouteConfig([
{ path: ‘/’, redirectTo: ‘/search’ },
{ path: ‘/search’, as: ‘search’, component: Search },
{ path: ‘/artist/:id’, as: ‘artist’, component: Artist }
])

This part is pretty obvious, an array with objects inside that define routes used in our application. Similar to Angular 1.x you can also set a default route using “redirectTo”.

export class App {
title: string;
constructor() {
this.title = ‘App title’;
}
}

Our main module only contains one property: “title”. That’s it for app.ts, we created our main module!

services/spotify.ts

Creating a service in angular2 is very simple compared to angular 1.x. Forget the angular.service syntax, we can write a Class using the normal TypeScript syntax that we can use later in our search and artist components.

The only angular part here is the @Injectable annotation, we use this to tell angular that this module is injectable. We use the native window.fetch method to talk to the Spotify API. The reason I didn’t use the HTTP provided by Angular is because it’s not fully implemented yet.

Check out these links to see what the response looks like.

Search API call

Artist API call

app/utils/fetch.ts

This file is nothing more than a collection of some functions that we need for responding to our window.fetch call.

Lets get started with building the actual pages, search and the artist detail page.

app/components/search/search.ts

@Component({
selector: ‘search’,
viewInjector: [Spotify]
})

We see something new here, the viewInjector. This is used to tell our component which service we are going to inject. I personally think viewInjector is a weird name, since it has nothing to do with the view.

<input #searchvalue (keyup)=”searchArtist($event, searchvalue.value)”/>

#searchvalue is similar to angular 1.x ng-model; we create a reference to the element.

(keyup)=”searchArtist($event, searchvalue.value)” links the function searchArtist to the keyup event.

If you are confused about the Angular 2 syntax, I recommend reading this article.

<li *ng-for=”#artist of artists”>

This is the repeater (ng-repeat) for showing the results.

<a [router-link]=”[‘/artist’, {id: artist.id}]”>

Again we use angular’s router-link directive, but this time we add a second parameter. An object containing the :id route parameter. This will generate a link: /artist/<id>

service: Spotify; 
constructor(service: Spotify) {
this.service = service;
}

We bind the Spotify service to this.service

searchArtist($event, value) { 
if (!value) { return; }
if (this.timeoutId) clearTimeout(this.timeoutId);
this.timeoutId = setTimeout(() => {
this.service.searchArtist(value)
.then(status)
.then(json)
.then((response) => {
this.setResults(response.artists.items);
})
}, 250);
}

searchArtist is the function that we linked to the input field in our template. Angular 2 doesn’t offer a debounce function yet, so I implemented my own. The debounce function is used to prevent an API call on every key down event.

setResults(artists: Array<Object>) { 
this.artists = artists;
}

Now this is where you start noticing how great Angular 2 is. We used a native HTTP call and we don’t have to use $scope.$apply. This view will automatically be updated when we change the value of “artists”.

So now we have written the code to generate a list of artists from user input that link to an artist page with the corresponding ID as route parameter. Let’s create the artist detail page.

app/components/artist/artist.ts

import { RouterLink, RouteParams } from ‘angular2/router’;

We will use the RouteParams to get the ID of the current page.

routeParam: RouteParams; 
image: string;
constructor(service: Spotify, routeParam: RouteParams) {
this.service = service;
this.routeParam = routeParam;
this.getArtist();
}

In addition to the Spotify service we also save the RouteParams. We use this in the getArtist function thats fired when this component is initiated.

getArtist() { 
this.service.getArtistById(this.routeParam.params.id)
.then(status)
.then(json)
.then((response) => {
this.artist = response;
this.image = response.images[0].url;
})
}

In the callback set the current artist and the image, which we use in the template to render the current artist’s name and photo.

Only one step left, rendering our application!

app/bootstrap.ts

var universalInjectables = [
routerInjectables,
Spotify,
bind(LocationStrategy).toClass(HashLocationStrategy)
];

We want to inject three things in our main application module: first is the routerInjectables, next is the Spotify service and last is the location strategy that we want to use (hash in this case).

bootstrap(App, [universalInjectables]);

And finally, we bootstrap our application. This will load the component (App) on our page.

Last but not least, generate the JavaScript from our TypeScript files and start the server

Generate the JS

tsc — watch -m commonjs -t es5 — emitDecoratorMetadata app/bootstrap.ts

Start the server. I use the http-server module from npm (npm install -g http-server).

http-server

Check out the demo here

I hope this post helps you to get started with Angular 2. Special thanks to Nadjib Amar for helping me with this post.