Build a Single Page Application with Angular 2

The much-awaited framework Angular 2 by Google is finally out and is ready for production. Now is the right time to start learning Angular 2. In this Angular 2 tutorial, we will build a simple single-page application with Angular 2. While doing so, we will understand a few core concepts in Angular 2 like components, directives, and routing.

Notice: This article has been updated for Angular 2.0 Final.

Getting Started

If you have explored a bit on Angular 2, you would already know that the initial setup of angular 2 apps is cumbersome. As it stands to this date, the starting point of any application development with Angular 2 should be the quickstart provided by the Angular team. There are two ways to get the quickstart running on our local systems. The first one involves following the official quickstart guide, the second option we have is to use the angular-cli tool. At the time of writing this post, the angular-cli project is still in beta, so we will leave it at that. For this Angular 2 tutorial, we follow the quickstart approach and continue building on that.
Before we move any further, if you are just getting started with Angular 2 and are interested in the overall architecture or how Angular 2 works or want to know in detail about the angular-cli tool, make sure you check out the below two articles.

DOWNLOAD

We will be using npm as our package manager, which is available with Node.js. Make sure you have Node.js installed. We will require node v5.x.x or higher and npm 3.x.x or higher. You can check the version by running the below commands.

node -v

npm -v

Create a directory for our project.

mkdir ciphertrick-spa
cd ciphertrick-spa

Now add these files into your working directory.

package.json

{
  "name": "ciphertrick-spa-app",
  "version": "1.0.0",
  "scripts": {
    "start": "tsc && concurrently \"npm run tsc:w\" \"npm run lite\" ",
    "lite": "lite-server",
    "postinstall": "typings install",
    "tsc": "tsc",
    "tsc:w": "tsc -w",
    "typings": "typings"
  },
  "license": "ISC",
  "dependencies": {
    "@angular/common": "2.0.0",
    "@angular/compiler": "2.0.0",
    "@angular/core": "2.0.0",
    "@angular/forms": "2.0.0",
    "@angular/http": "2.0.0",
    "@angular/platform-browser": "2.0.0",
    "@angular/platform-browser-dynamic": "2.0.0",
    "@angular/router": "3.0.0",
    "@angular/upgrade": "2.0.0",
    "core-js": "^2.4.1",
    "reflect-metadata": "^0.1.3",
    "rxjs": "5.0.0-beta.12",
    "systemjs": "0.19.27",
    "zone.js": "^0.6.23",
    "angular2-in-memory-web-api": "0.0.20",
    "bootstrap": "^3.3.6"
  },
  "devDependencies": {
    "concurrently": "^2.2.0",
    "lite-server": "^2.2.2",
    "typescript": "^2.0.2",
    "typings":"^1.3.2"
  }
}
tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "outDir": "app/transpiled-js",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  }
}
typings.json

{
  "globalDependencies": {
    "core-js": "registry:dt/core-js#0.0.0+20160725163759",
    "jasmine": "registry:dt/jasmine#2.2.0+20160621224255",
    "node": "registry:dt/node#6.0.0+20160909174046"
  }
}
systems.config.js

/**
 * System configuration for Angular samples
 * Adjust as necessary for your application needs.
 */
(function (global) {
  System.config({
    paths: {
      // paths serve as alias
      'npm:': 'node_modules/'
    },
    // map tells the System loader where to look for things
    map: {
      // our app is within the app folder
      app: 'app',
      // angular bundles
      '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
      '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
      '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
      '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
      '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
      '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
      '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
      '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
      // other libraries
      'rxjs':                       'npm:rxjs',
      'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api',
    },
    // packages tells the System loader how to load when no filename and/or no extension
    packages: {
      app: {
        main: './transpiled-js/main.js', //path to main.js
        defaultExtension: 'js'
      },
      rxjs: {
        defaultExtension: 'js'
      },
      'angular2-in-memory-web-api': {
        main: './index.js',
        defaultExtension: 'js'
      }
    }
  });
})(this);

All of the files are similar to what is provided by the Angular 2 quickstart team, except added a single line as "outDir": "app/transpiled-js" in tsconfig.json, this is to separate out the transpiled js from our working TypeScript code. Also, we will have to change the path to main.js in systems.config.js. Don’t worry about what is main.js, it is the transpiled js version of main.ts file to which we will come later in the tutorial.

Once this is done then the next step is to install all the dependencies.

npm install

This should ideally also install the typings, but if in case they are missed out, you can install them manually by running the below command.

typings install

Note– If you are on windows, run your command line as administrator if possible.

Now that we are done with the dependencies and typescript setup, it’s time to start building our app. Create a folder named app. This is where we will pace all our Angular 2 app code.

mkdir app
cd app

Creating our first Angular 2 Module

An Angular 2 app comprises a collection of modules and every app will have at least one module, which would be the root module.

Create a file named app.module.ts inside the app folder.

app/app.module.ts

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

@NgModule({
  imports:      [ BrowserModule ], //other modules the app depends on
  declarations: [], // declare all derectives and components
  bootstrap : [] // root component to bootstarp
})
export class AppModule { }

 
The @NgModule decorator is used to define the metadata for our module. BrowserModule from @angular/platform-browser is the most important module which is required by the app that runs in the browser.

The declarations and bootstrap are empty, we will add our components there once we create one.

Creating our root component

Every Angular 2 app must have a root component, let’s create one. Create a file named app.component.ts and add the following code.

app/app.component.ts

import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    templateUrl: './app/app.component.html',
})
export class AppComponent { }

Using the @Component decorator we are notifying Angular to treat the AppComponent class as a component. We have specified a selector and a templateUrl. Components are nothing but Angular 2 directives with a template. Now let’s create a template for our component.

Create a file named app.component.html and add the following code.

app/app.component.html
<nav class="navbar navbar-default">
  <div class="container-fluid">
    <div class="navbar-header">
      <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
        <ul class="nav navbar-nav">
          <li><a>Home</a></li>
          <li><a>About</a></li>
        </ul>
      </div>
    </div>
  </div>
</nav>
<div class="container">
  <div class="row">
    <!-- routing here -->
  </div>
</div>

 
Don’t worry about the styling, I’m using bootstrap.css but you may choose your own or ignore that all together.

Now that our root component is ready, we have to add it to our app module.

app/app.module.ts

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent }   from './app.component';

@NgModule({
  imports:      [ BrowserModule ], //other modules the app depends on
  declarations: [ AppComponent ], // declare all derectives and components
  bootstrap : [ AppComponent ] // root component to bootstarp
})
export class AppModule { }

We first imported our AppComponent and added it to declarations and bootstrap.

Bootstraping our root Module

One of the most important thing in an Angular 2 application is to bootstrap the root module. This by convention is done in a file named main.ts.

main.ts

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);

Bootstrapping is platform specific and since our app would run on browsers we would bootstrap it for the browser.

Adding index.html to load our app

Now that we have the backbone of our Angular 2 app ready, all we need is a web page to load our app into the browser. Create a file named index.html just outside the app folder.

index.html
<html>
  <head>
    <title>CipherTrick Application</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="styles.css">
    <!-- 1. Load libraries -->
     <!-- Polyfill(s) for older browsers -->
    <script src="node_modules/core-js/client/shim.min.js"></script>
    <script src="node_modules/zone.js/dist/zone.js"></script>
    <script src="node_modules/reflect-metadata/Reflect.js"></script>
    <script src="node_modules/systemjs/dist/system.src.js"></script>
    <!-- 2. Configure SystemJS -->
    <script src="systemjs.config.js"></script>
    <script>
      System.import('app').catch(function(err){ console.error(err); });
    </script>
  </head>
  <!-- 3. Display the application -->
  <body>
    <app-root>Loading...</app-root>
  </body>
</html>

Here we are loading a few files including our systems.config.js. We have also added our root component selector app-root, this is where our app will load. Also, we have added a bit of application-wide styles in styles.css which you may find in the downloaded code, or browse here.

Run Our Angular 2 Application

To run the application hit the below command.

npm start

If you have followed everything correctly, you should see a page with a navbar and two links running on http://localhost:3000. Just like it’s shown in the below image.

Alright, so now that we have a basic app running, it’s time to add a few more components to our application.

Creating child Components

For our tutorial, we will create two components, which will represent our home and about page respectively.
Let us first start with the HomeComponent. Create a folder named home under the app directory.
By the endorsed style guide convention we name the files related to components as [componentName].component.[type]. So the TypeScript file for our home component would be named as home.component.ts.

app/home/home.component.ts
import {Component} from '@angular/core';

@Component({
    selector: 'app-home',
    template: `<h1>{{welcome}}</h1>`
})
export class HomeComponent {
    welcome : string;
    constructor(){
        this.welcome = "Welcome to home page";
    };
};

 
This is a very basic component where we are only displaying a simple welcome message. Notice we are using a template instead of a templateUrl as we don’t have much in our markup. Similarly, let’s create our AboutComponent.

app/about/about.component.ts
import {Component} from '@angular/core';

@Component({
    selector: 'app-about',
    template: `<h1>{{welcome}}</h1>`
})
export class AboutComponent {
    welcome : string;
    constructor(){
        this.welcome = "Welcome to about page"
    };
};

We must not forget to declare our components inside our AppModule.

app/app.module.ts

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent }   from './app.component';
import { HomeComponent } from './home/home.component'; //import home components
import { AboutComponent } from './about/about.component'; //import about component

@NgModule({
  imports:      [ BrowserModule ], //other modules the app depends on
  declarations: [ AppComponent, AboutComponent, HomeComponent ], // declare all derectives and components
  bootstrap : [ AppComponent ] // root component to bootstarp
})
export class AppModule { }

Adding routing with Component Router in Angular 2

We already have our components ready. But to display them on click of the navigation links we will need to hook up routes to those. We will do this with the help of the Routing module of the component router in Angular 2.

Create a file named app.routing.ts under the app folder.

app/app.routing.ts

import { ModuleWithProviders }  from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { HomeComponent } from './home/home.component'; //import home components
import { AboutComponent } from './about/about.component'; //import about component

const appRoutes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: 'about', component: AboutComponent },
  { path: '', component: HomeComponent, pathMatch: 'full'} // redirect to home page on load
];

export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);

Our appRoutes is an array of objects of type Routes. Each object corresponds to a path in our application and must have at least two parameters: a path to which our app will navigate (this will be shown in our URL) and a component to load for that corresponding path.

The last object in the appRoutes array is the default redirect to the Home page when our app loads. We are using the forRoot method from RoutingModule because we are configuring routes for our root component.
ModuleWithProviders is usually used when you want to export Providers along with Routes. But we aren’t exporting any providers, so you may remove it if you wish.

Once we have the routine in place, we have to inform our AppModule about it. For the last time, update your app.module.ts file to as follows.

app/app.module.ts

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent }   from './app.component';
import { HomeComponent } from './home/home.component'; //import home components
import { AboutComponent } from './about/about.component'; //import about component
import { routing }  from './app.routing';

@NgModule({
  imports:      [ BrowserModule, routing ], //other modules the app depends on
  declarations: [ AppComponent, AboutComponent, HomeComponent ], // declare all derectives and components
  bootstrap : [ AppComponent ] // root component to bootstarp
})
export class AppModule { }

Here we are adding routing as a dependency for our application.

Next, we have to add router-outlet directive into the template of our root component. This is where all our child routes load. We will also add routerLink to our Home and About navigation links.

app/app.component.html
<nav class="navbar navbar-default">
  <div class="container-fluid">
    <div class="navbar-header">
      <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
        <ul class="nav navbar-nav">
          <li><a routerLink="/home" routerLinkActive="active">Home</a></li>
          <li><a routerLink="/about" routerLinkActive="active">About</a></li>
        </ul>
      </div>
    </div>
  </div>
</nav>
<div class="container">
  <div class="row">
    <!-- routing here -->
    <router-outlet></router-outlet>
  </div>
</div>

The routerLinkActive directive adds the active class to the link that is active. This is mainly to highlight the active link, the corresponding CSS is added in style.css

Now the final thing left out is setting the base href. Add it below the opening of the head tag in your index.html.

index.html
<head>
<base href="/">
...

Now when you run the app using the npm start command, you should see the home page load by default. You would also be able to navigate using the navigation links provided in the nav bar.

There you have it, your first Single Page Application using Angular 2

Quicksetup

To quickly get the app running follow the below steps.

  1. git clone https://github.com/rahil471/single-page-application-angular2.git
  2. Navigate into the directory using command line interface
  3. Run npm install
  4. Run npm start

Conclusion

In this Angular 2 tutorial, we learned to create a simple single-page application with Angular 2. We also learned to create components in Angular 2 and link them up using routing. Hope this tutorial will set a strong base for you to build larger apps with Angular 2.
If you have any queries you may comment below the post or you may reach me directly via twitter.

Facebook
Twitter
LinkedIn
Pinterest

Table of Contents

Related posts