Services
Until an app is connected to a backend, it's not very useful. This is where Angular2 services come in.
Services:
- remove data access from the component
- give us an exportable, reusable way of accessing backend data
- allow a way to normalize many different incoming data streams for all service consumers
To that end, Covalent provides several services to simplify routing and RESTful calls:
- HttpInterceptorService
- RESTService
In this lab, we will create our own MessagesService
that inherits the covalent RESTService.
Setup
Stash away any items not needed for this lab
git stash
Checkout the repo at the start tag
git checkout tags/lab/mock-api/message-schema -b services-lab
Start the local angular-cli server:
ng serve
you should see:
Open a new tab or console. Start the Data Server in a new tab/console:
npm run start-api
You should see:
Finally, point a browser to http://localhost:4200
A login should load! Let's get to work!
Take a look at /src/services/messages.service.ts
:
import { Injectable } from '@angular/core';
import { Response } from '@angular/http';
import { HttpInterceptorService } from '@covalent/http';
export interface IMessage {
id?: number;
title?: string;
sender?: string;
body?: string;
received_at?: any;
}
@Injectable()
export class MessagesService {
constructor(private _http: HttpInterceptorService) {}
query(): any {
return this._http.get('data/messages.json')
.map((res: Response) => {
return res.json();
});
}
get(id: number): any {
return this._http.get('data/messages.json')
.map((res: Response) => {
let message: any;
res.json().forEach((s: any) => {
if (s.id === id) {
message = s;
}
});
return message;
});
}
}
And point your browser to http://localhost:4200/messages to see the resulting data:
First thing to do is import the covalent RESTService:
import { HttpInterceptorService, RESTService } from '@covalent/http';
We can remove Response
from the @angular/http
library since RESTService takes care of it, but we need to import Headers
in order to customize our REST calls.
import { Headers } from '@angular/http';
We need to add a link to our mock-api server. This has conveniently been supplied for us in ../config/api.config
.
import { MOCK_API } from '../config/api.config';
Now we can make MessageService
inherit the RESTService
class:
export class MessagesService extends RESTService<IMessage> {
}
Since RESTService already implements query()
and get()
, we can remove those. Lets specify some parameters that are specific to the message service:
export class MessagesService extends RESTService<IMessage> {
constructor(private _http: HttpInterceptorService) {
super(_http, {
baseHeaders: new Headers({'Accept': 'application/json'}),
baseUrl: MOCK_API,
path: '/messages',
});
}
}
Done! Our new messages.service.ts
should now look like this:
import { Injectable } from '@angular/core';
import { Headers } from '@angular/http';
import { HttpInterceptorService, RESTService } from '@covalent/http';
import { MOCK_API } from '../config/api.config';
export interface IMessage {
id?: number;
title?: string;
sender?: string;
body?: string;
received_at?: any;
}
@Injectable()
export class MessagesService extends RESTService<IMessage> {
constructor(private _http: HttpInterceptorService) {
super(_http, {
baseHeaders: new Headers({'Accept': 'application/json'}),
baseUrl: MOCK_API,
path: '/messages',
});
}
}
Lets save and reload our browser: http://localhost:4200/messages
Real data from a real http endpoint!
Wait... Something is off. Lets use console.log
to see if we can figure out what's happening.
in src/app/messages/messages.component.ts
add a line after consuming your message packet from the service:
loadMessages(): void {
this._loadingService.register('messages.list');
this._messagesService.query().subscribe((messages: IMessage[]) => {
this.messages = messages;
console.log(messages);
Open up your browser debug console, and drill into one of the array objects:
Now, open src/app/messages/messages.component.html
and find where Sender
and Received At
are being displayed:
<template let-item let-last="last" ngFor [ngForOf]="messages">
<md-nav-list>
<a md-list-item [routerLink]="['/messages', item.id]">
<md-icon md-list-avatar>message</md-icon>
<h3 md-line> {{item.title}} </h3>
<span hide-xs flex="30">
{{item.sender}}
</span>
<span hide-xs flex="40" class="text-right md-body-1 pad-right">
{{item.received_at | date:'short'}}
</span>
<span flex="10"></span>
</a>
</md-nav-list>
<md-divider *ngIf="!last" md-inset></md-divider>
</template>
Notice anything?
Now that you've found the issue and fixed it, lets reload: http://localhost:4200/messages
w00t! Congratulations!
For the completed lab, go to https://github.td.teradata.com/ux/covalent-training/tree/feature/mock-api
Thanks!