Building Easy Stats with Angular 2, D3 and LoopBack

Previously on How to build Easy Stats with LoopBack - Part 2 I explained how to make a more advanced use of the loopback-stats-mixin. Now we want to have some fun and represent that datasets into some good looking charts made on Angular 2 and D3.

IMPORTANT: A revised version for this tutorial has been published and this version is kind of deprecated. My recommendation for you is to follow the revised version that you will able to find IN HERE.

Project Description

In this tutorial we are going to create an Angular 2 App using the Angular 2 Seed, making a Stats Component that will get the datasets resulting from the API we built in Part 1 and Part 2.

Later on, we will be using D3 to create a chart component that will help us to represent the data we created in my previous posts.

Articles Index

  • Part 1: Setting up the REST API.
  • Part 2: Creating Stats Endpoints.
  • Part 3: Setting up Angular 2 App.
  • Part 4: Build Chart Component

Requirements

  • Node JS
  • NPM
  • TypeScript
  • GitHub
  • Follow Part 1 and Part 2 if you care about how we got the datasets for the charts.

Setup Angular Project

For this project we are going to use the Angular 2 Seed from Angular’s GitHub Account.

1
2
3
4
5
$ git clone https://github.com/angular/angular2-seed
$ mv angular2-seed easy-stats/client
$ cd easy-stats/client
$ npm install -g webpack webpack-dev-server typings typescript
$ npm install

Since the default API Port is 3000 as well as the Angular 2 Seed, we need to modify one of these, in this case I will update the package.json from the NG2 App to serve in port 3030.

1
2
3
{
"server": "node node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --colors --progress --display-error-details --display-cached --port 3030 --content-base src",
}

Now you can start the Angular 2 App by running the following command within the easy-stats/client directory.

1
$ npm start

To verify that the seed was correctly installed and started open your browser in the following route http://localhost:3030/

This tutorial is based in version 2.0.0-beta.15 but I will try to keep it valid after first stable version is released.

Fun Time

Ok I won’t go in details about the basic structure of an Angular 2 Application since there are a good amount of published blogs that talks about the basics, what I want to do is to have some fun and go beyond.

So… if you feel you need to understand the basics I recommend you to read the Angular’s Official Getting Started then you can come back here and continue the tutorial.

Create Stats Files

1
$ mkdir easy-stats/client/src/app/components/stats

Now create stats.ts, stats.service.ts, stats.html and stats.css files within that directory

1
2
3
4
5
+ stats
|- stats.ts
|- stats.service.ts
|- stats.html
|- stats.css

Create Stats Service

In order to communicate our NG2 App with our LB API, we need to create an injectable service that will later use as provider in our Stats Component.

File: src/app/components/stats/stats.service.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';
import {Observable} from 'rxjs/Observable';

@Injectable()
export class StatsService {

private url: string = 'http://localhost:3000/api';

constructor(private http: Http) { }

byCustomer(id: any, range: string): Observable<any> {
return this.http.get(this.url + '/customers/' + id +'/stats?range=' + range);
}
}

Since created some endpoints to get statistical information regarding specific customers then we need to create a method within our service that will help us to gather that information.

Seems simple huh? well for those who does not know, we addressed a grouping behavior in order to make just 1 call to fetch every statistical information in 1 API Request.

If you are not aware of how to create the API to serve this information and now you are interested, see Part 1 and Part 2.

Now we can inject the StatsService into our stats component we about to create.

Create Stats Component

We need to create a component that will get the datasets from our LoopBack application, for this we need to import the StatsService and include it as provider.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import {Component} from 'angular2/core';
import {StatsService} from './stats.service';

@Component({
selector: 'stats',
templateUrl: 'app/components/stats/stats.html',
styleUrls: ['app/components/stats/stats.css'],
providers: [StatsService],
directives: [],
pipes: []
})

export class Stats {

private customerId: any;
private range: string = 'weekly';

constructor(private statsService: StatsService) { }

ngOnInit() {
}

getStats() {
this.statsService.byCustomer(this.customerId, this.range)
.subscribe(stats => console.log(stats.json()));
}
}

The customerId and range properties will help us to create a small form that will help us to get specific statistics in range but also from customer Ids.

I will leave the customerId type as any, since can be numeric sql environments or string when using mongodb.

I created the getStats method so we can bind it to a button in our view, this method will subscribe to the Observable we got from the StatsService.byCustomer method.

For now, we are just doing a console log to verify we are getting the data from our API, the next step will be to connect with a D3 Chart Component we are going to create.

Adding the View

Modify the stats.html file adding the following markup:

1
2
3
4
5
6
<h1>Easy Stats</h1>
<label for="customerId">Customer Id:</label>
<input name="customerId" type="text" [(ngModel)]="customerId" placeholder="customerId" />
<label for="range">Range:</label>
<input name="range" type="text" [(ngModel)]="range" placeholder="range" />
<button (click)="getStats()">Get Stats</button>

Update seed-app.ts

Now we need to say the angular app to use our Stats Component by configuring the seed-app.ts file as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import {Component} from 'angular2/core';
import {Router, RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
import {Stats} from './components/stats/stats';

@Component({
selector: 'seed-app',
providers: [],
pipes: [],
directives: [ROUTER_DIRECTIVES],
templateUrl: 'app/seed-app.html',
})

@RouteConfig([
{ path: '/', component: Stats, name: 'Stats', useAsDefault: true }
])

export class SeedApp {
constructor() {}
}

Also I wanted to clean the app by removing the built in components and leaving only the Stats component ponted to the root path.

Before Test

Before testing the app you need to make sure your API is running and you have set a number of customers and orders.

Also, we did not setup any datasource to our API, if you stop the process you will lose your data, therefore you won’t be able to test this app.

To avoid that behaviour you will need to Setup a DataSource in LoopBack.

Test

If you start the server again $ npm start you will be able to see a form that will help you get the information from the API we built.

For now, we are able to verify the information on the Browser’s Console.

What is next?

In my next blog posts we are going to create our D3 Chart Component in Angular 2, also give some styling to the page by either using Angular Material 2 or Bootstrap 4.

If you want to help decide between Angular Material 2 or Bootstrap 4, leave a comment and we will decide together.

If you like this series and want be aware of next releases and new packages, follow me on Twitter @johncasarrubias and if you feel it leave a comment here.

Thanks for reading.


Comments:

...