This is the first part of Rewriting an Employee Tracker using Angular 2 and TypeScript Series.
The source code for this tutorial series is published on GitHub. Demo application is hosted in Microsoft Azure.
Part 1: Create an Angular 2 SPA in TypeScript
In previous tutorial series of building an Employee Tracker, we created the front end in Angular 1.5.5 and the back end in ASP.NET Web API 2.2.
In this tutorial, we will use Visual Studio Code to build the initial structure of the Angular 2 Single-Page Application (SPA) in TypeScript.
Client-Side Technologies:
The application structure, styles, and patterns follow the recommendations outlined in the official Angular 2 Style Guide.
I use the official Angular 2 Developer Guide as a reference to write this tutorial series.
Prerequisites
The following are required to complete this tutorial:
- Build the QuickStart app if you are new to Angular 2
- Install Node.js and npm (Nods.js > 6.3.x and npm > 3.10.x) on your machine if you haven’t done so already
Task 1. Set up the Project Structure
I prefer to organize my project based on components/modules. Building a maintainable, scalable, and well-organized application should start from the beginning. Using DRY and SRP patterns, we will create smaller code files that each handle one specific job. This approach has helped me personally to locate, enhance, and debug requested features from clients quickly.
-
Let’s creating folders and copying files to C:\_tutorials\ng2-employee-tracker from GitHub as listed below:
ng2-employee-tracker
|--api
|--dashboard.json
|--employees.json
|--app
|--dashboard
|--ng2-nvd3.ts
|--employees
|--layout
|--content
|--css
|--animate.css
|--loading-bars.css
|--sb-admin-2.css
|--images
|--favicon.ico
|--loading-bars.svg
|--js
|--loading-bars.js
|--sb-admin-2.js
|--package.json
|--systemjs.config.js
|--tsconfig.json
|--typings.json
-
Lines 21-24 list the package definition and configuration files:
- package.json: defines scripts and serves as documentation for what packages the Employee Tracker depends on.
- systemjs.config.js: loads application and library modules.
- tsconfig.json: is a configuration file to guide the TypeScript compiler as it generates JavaScript files.
- typings.josn: is a TypeScript definition file.
See Add package definition and configuration files from 5 Minute QuickStart
for explanations.
Task 2. Install the Packages
Open the terminal window, enter the npm install
command to install all listed packages and libraries in package.json using npm
.
Task 3. Create startup page
-
Add the index.html file to the ng2-employee-tracker folder.
-
Replace the code in this file with the following:
<!DOCTYPE html>
<html >
<head>
<!-- Set the base href -->
<script>document.write('<base href="' + document.location + '" />');</script>
<title>Angular 2 Employee Tracker App</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 1. Load css -->
<link rel='stylesheet prefetch' href='node_modules/bootstrap/dist/css/bootstrap.min.css'>
<link rel="stylesheet" href="content/css/sb-admin-2.css">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css" />
<link rel="stylesheet" href="node_modules/nvd3/build/nv.d3.min.css"/>
<link rel="stylesheet" href="content/css/animate.css" />
<link rel="stylesheet" href="content/css/loading-bars.css" />
<!-- 2. Load libraries -->
<!-- 2.1 Polyfill(s) for older browsers -->
<script src="//cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.0/es6-shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.min.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/rxjs/bundles/Rx.min.js"></script>
<!-- Fix the Date and Currency pipes in mobile safari -->
<script src="//cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en"></script>
<!-- 2.2 Vendor js libraries -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="node_modules/d3/d3.min.js"></script>
<script src="node_modules/nvd3/build/nv.d3.min.js"></script>
<!-- 3. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err) { console.error(err); });
</script>
</head>
<body>
<!-- 4. Display the application -->
<employee-tracker-app>
<!-- Show simple splash screen-->
<div class="splash">
<div class="color-line"></div>
<div class="splash-title">
<h1>Angular 2 Employee Tracker</h1>
<img src="content/images/loading-bars.svg" width="64" height="64" title="" alt="" />
</div>
</div>
</employee-tracker-app>
</body>
</html>
The index.html file serve as our startup page. It performs the following functions:
- loads our resources (.css and .js)
- configures
SystemJS
to load library modules and launch our application by running the AppModule
in the main.ts file - renders our application’s component between the
employee-tracker-app
tags - shows our splash screen
Task 4. Bootstrap our application
-
Add the main.ts file to the app folder.
-
Replace the code in this file with the following:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
Line 8 bootstraps the imported AppModule
from app.module.ts file using the Just in Time
(JIT) complier to launch the application.
Task 5. Create the root module
By convention, every Angular app has a root module class called AppModule
in app.module.ts file. The @NgModule decorator allows us to bundle components, services, pipes, and directives at the module level. If you want to learn more about the benefits of using @NgModule
, please check out Rob Wormald’s blog post.
-
Let’s add app.module.ts file to the app folder.
-
Replace the code in this file with the following:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { AppComponent } from './app.component';
import { SidebarComponent } from './layout/sidebar.component';
import { DashboardModule } from './dashboard/dashboard.module';
import { EmployeesModule } from './employees/employees.module';
import { routing } from './app.routing';
@NgModule({
imports: [ BrowserModule, DashboardModule, EmployeesModule, HttpModule, routing ],
declarations: [ AppComponent, SidebarComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule {}
-
Line 17 imports the following supporting modules whose exported components, directives, or pipes are referenced by the component declared in the AppModule
.
BrowserModule
: provides critical services that are essential to launch and run our app in the browser DashboardModule
: provides collections of Dashboard
functionality EmployeesModule
: provides collections of Employees
functionality HttpModule
: provides http
services routing
: is a Router module which provides the application-wide configured services with routes in the root module
-
Line 18 declares a list of components (AppComponent
, SidebarComponent
) that belong to the AppModule
.
-
Line 19 bootstraps the root component named AppComponent
when Angular starts the application.
-
Line 22 exports the AppModule
so that the main.ts file can import it.
Task 6. Configure routes for the Router
The application will have one Router which enables navigation from one view to the next. To learn more about Routing & Navigation
, please see the official doc here.
-
Add the app.routing.ts file to the app folder.
-
Replace the code in this file with the following:
import { Routes, RouterModule } from '@angular/router';
const appRoutes: Routes = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: 'employees', redirectTo: '/employees' },
{ path: '**', redirectTo: '/dashboard' }
];
export const routing = RouterModule.forRoot(appRoutes, { useHash: true });
We configure our Router with three routes:
- 1st Route: when initial relative URL is empty (for example: http://localhost:3000) , redirect to another route whose path segment is
/dashboard
- 2nd Route: when URL matches the path segment
/employees
, redirect to another route whose path segment is /employees
- 3rd Route: when URL doesn’t match any routes defined in our configuration, redirect to another route whose path segment is
/dashboard
We pass our three routes into the RouterModule.forRoot
method which returns a module containing the configured Router. We export this module as the routing
token.
NOTE: We registered routing
with the root module named AppModule
.
Task 7. Create our root component and its view
-
Add the root component named app.component.ts file to the app folder.
-
Replace the code in this file with the following:
import { Component } from '@angular/core';
@Component ({
selector: 'employee-tracker-app'
,templateUrl: 'app/app.component.html'
})
export class AppComponent {}
The AppComponent
is our application shell.
-
Add the view named app.component.html file to the app folder.
-
Replace the code in this file with the following:
<div id="wrapper">
<!-- Navigation Area -->
<et-sidebar></et-sidebar>
<!-- End Navigation Area -->
<!-- Content Area -->
<div id="page-wrapper">
<!-- Routed View -->
<router-outlet></router-outlet>
</div>
<!-- End Content Area -->
</div>
The app.component.html file contains the master layout for our HTML. It provides a shell
with two regions: a navigation area and a content area. The navigation area renders the sidebar
view between the et-sidebar
tags. The content area uses router-outlet
directive to display the views produced by the Router. In other words, when you click a navigation link, it’s corresponding view is loaded in the content area.
Task 8. Create the Sidebar component and its view
-
Add the sidebar.component.ts file to the layout folder.
-
Replace the code in this file with the following:
import { Component } from '@angular/core';
@Component ({
selector: 'et-sidebar'
,templateUrl: 'app/layout/sidebar.component.html'
})
export class SidebarComponent {
heading = 'Angular 2 Employee Tracker App';
}
The navigation area of the AppComponent
uses et-sidebar
to display the sidebar
view.
-
Add the view named sidebar.component.html file to the layout folder.
-
Replace the code in this file with the following:
<nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0">
<!-- navbar-header -->
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">{{heading}}</a>
</div>
<!-- /.navbar-header -->
<!-- navbar-top-links -->
<ul class="nav navbar-top-links navbar-right">
<!-- dropdown envelope icon -->
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
</a>
<!-- dropdown-messages -->
<ul class="dropdown-menu dropdown-messages">
<li>
<div class="text-center small">
You have 2 tutorials
</div>
</li>
<li class="divider"></li>
<li>
<a href="https://www.cc28tech.com/angular-2-employee-tracker-typescript-part-1" target="_blank">
<div class="small">
Part 1:
<span class="text-info">
Create an Angular 2 SPA in TypeScript
</span>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a href="https://www.cc28tech.com/angular-2-employee-tracker-typescript-part-2" target="_blank">
<div class="small">
Part 2:
<span class="text-info">
Create Angular 2 Feature Modules in TypeScript
</span>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a class="text-center text-info small" href="https://www.cc28tech.com" target="_blank">
<div class="text-info">
See Other Tutorials
</div>
</a>
</li>
</ul>
<!-- /.dropdown-messages -->
</li>
<!-- /.dropdown envelope icon -->
<!-- dropdown user icon -->
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
</a>
<!-- dropdown-user -->
<ul class="dropdown-menu dropdown-user">
<li>
<a href="https://www.cc28tech.com/cathy-wun" target="_blank">
<div class="text-center small">
<span class="text-info">About Me</span>
</div>
</a>
</li>
</ul>
<!-- /.dropdown-user -->
</li>
<!-- /.dropdown user icon -->
</ul>
<!-- /.navbar-top-links -->
<!-- navbar-static-side -->
<div class="navbar-default sidebar" role="navigation">
<!-- sidebar-collapse -->
<div class="sidebar-nav navbar-collapse">
<ul class="nav" id="side-menu">
<li>
<a routerLink="/dashboard" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">
<span class="nav-label">Dashboard</span>
</a>
</li>
<li>
<a routerLink="/employees" routerLinkActive="active">
<span class="nav-label">Employees</span>
</a>
</li>
</ul>
</div>
<!-- /.sidebar-collapse -->
</div>
<!-- /.navbar-static-side -->
</nav>
The sidebar.component.html uses Bootstrap for quick styling and building responsive layouts. It uses routerLink
directive to represent navigation menu items.
-
We have the following links in navigation menu:
When you click the Dashboard link in the navigation menu, the Dasboard
view will be placed in the content area of the AppComponent
view:
When you click the Employees link in the navigation menu, the Employees
view will be placed in the content area of the AppComponent
view:
In the next tutorial, we will build the Angular 2 Dashboard and Employees Feature Modules using TypeScript.
The source code for this tutorial series is published on GitHub. Demo application is hosted in Microsoft Azure.
References