Sunday, August 21, 2016

22. Connecting to the Server

Connecting to the Server

A Simple RESTful API

Building RESTful API is beyond scope of angular since its server side technology like node, ruby on rails etc. But as an angular developer, need to know how to connect to RESTful API. Will connect to a fake RESTful api

https://jsonplaceholder.typicode.com/

or Google jsonplaceholder

Learn how to communicate with server in your angular apps

.e.g

https://jsonplaceholder.typicode.com/posts

Getting Data from the Server

Will use http class in angular. Use it to make ajax calls to server.

get()
post()
put() // for update
patch() //for update
delete()
head() // get meta data about resource. Used to get existence of resource

Should make http calls in Service.

Create new file post.service.ts

import {Http} from '@angular/http';
import 'rxjs/add/operator/map';

export class PostService{
    constructor(private _http: Http){

    }

    getPost(){
        return this._http.get("https://jsonplaceholder.typicode.com/posts")
            .map(res => res.json())
    }
}

Sending Data to the Server

import {Http} from '@angular/http';
import 'rxjs/add/operator/map';

export class PostService{

private _url = "https://jsonplaceholder.typicode.com/posts";

    constructor(private _http: Http){

    }

    getPosts(){
        return this._http.get(this._url)
            .map(res => res.json())
    }

    createPost(post){
        this._http.post(this._url,JSON.stringify(post))
            .map(res => res.json());
    }
}


Dependency Injection

Our service is ready. Now need to inject it into our component. First need to mark this class as available for dependency injection.

In post.service.ts, add

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


@Injectable()

app.component.ts

import {Component} from '@angular/core';
import {PostService} from './post.service';
import {HTTP_PROVIDERS} from '@angular/http';

@Component({
  moduleId: module.id,
  selector: 'app-root',
  template: `
    `,
    providers:[PostService, HTTP_PROVIDERS]
})
export class AppComponent {
    constructor(private _postService: PostService){
        this._postService.getPosts()
            .subscribe(posts => console.log(posts));
    }    

}

Component's Lifecycle Hooks

Even though our code works, doesn't follow the best practises.  COnstructor should not contain costly operations.

Components have a lifecycle hooks that we can tap into during the key moments of a component's lifecycle.

OnInit
OnDestroy
DoCheck
OnChanges
AfterContentInit
AfterContentChecked
AfterViewInit
AfterViewChecked

We need to implement one for more interfaces. Each interface has a method that we need to add to our components. When the right moment arrives, Angular will call these methods. For e.g. we can implement the OnInit interface when the component is first instantiated. 

import {Component} from '@angular/core';
import {PostService} from './post.service';
import {HTTP_PROVIDERS} from '@angular/http';
import {OnInit} from '@angular/core';

@Component({
  moduleId: module.id,
  selector: 'app-root',
  template: `
    `,
    providers:[PostService, HTTP_PROVIDERS]
})
export class AppComponent implements OnInit {
    constructor(private _postService: PostService){

    }

    ngOnInit(){
        // this method will be called when the component is instantiated. Its called after constructor
        // constructor should contain light weight operations. IF need to connect to server, should do so in ngOnInit
        this._postService.getPosts()
            .subscribe(posts => console.log(posts));        
    }        

}

To implement more than one interface

export class AppComponent implements OnInit, OnDestroy {

Static Type Checking

Create Post interface

export interface Post{
    // what fields do we need here?
    userId: number;
    id?: number;
    title: string;
    body: string;

}

post.service.ts

import {Http} from '@angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import {Injectable} from '@angular/core';
import {Post} from './post';

@Injectable()
export class PostService{

private _url = "https://jsonplaceholder.typicode.com/posts";

    constructor(private _http: Http){

    }

    getPosts() : Observable<Post[]>{
        return this._http.get(this._url)
            .map(res => res.json())
    }

    createPost(post : Post){
        this._http.post(this._url,JSON.stringify(post))
            .map(res => res.json());
    }

}

app.component.ts

import {Component} from '@angular/core';
import {PostService} from './post.service';
import {HTTP_PROVIDERS} from '@angular/http';
import {OnInit} from '@angular/core';

@Component({
  moduleId: module.id,
  selector: 'app-root',
  template: `
    `,
    providers:[PostService, HTTP_PROVIDERS]
})
export class AppComponent implements OnInit {
    constructor(private _postService: PostService){
        this._postService.createPost({userId: 1, title: "a", body: "b"});
    }

    ngOnInit(){
        // this method will be called when the component is instantiated. Its called after constructor
        // constructor should contain light weight operations. IF need to connect to server, should do so in ngOnInit
        this._postService.getPosts()
            .subscribe(posts => console.log(posts[0].userId));        
    }       

}

Showing a Loader Icon

When getting content from server, useful to show a loader icon to user

import {Component} from '@angular/core';
import {PostService} from './post.service';
import {HTTP_PROVIDERS} from '@angular/http';
import {OnInit} from '@angular/core';

@Component({
  moduleId: module.id,
  selector: 'app-root',
  template: `
        <div *ngIf="isLoading">Getting data...</div>
    `,
    providers:[PostService, HTTP_PROVIDERS]
})
export class AppComponent implements OnInit {
    isLoading = true;

    constructor(private _postService: PostService){
        this._postService.createPost({userId: 1, title: "a", body: "b"});
    }

    ngOnInit(){
        this._postService.getPosts()
            .subscribe(posts => {
                this.isLoading = false;
                console.log(posts[0].userId);
            });        
    }       

}

Google 'font awesome'

Go to http://fontawesome.io/get-started/

add to index.html in head tag...

  template: `
        <div *ngIf="isLoading">
            <i class="fa fa-spinner fa-spin fa-3x"></i>
        </div>
    `,

GitHub Example

app.component.ts

import {Component} from '@angular/core';
import {GitHubProfileComponent} from './github-profile.component';

@Component({
  moduleId: module.id,
  selector: 'app-root',
  directives:[GitHubProfileComponent],
  template: `
        <github-profile></github-profile>
    `
})
export class AppComponent {
    

}


github.service.ts

import {Injectable} from '@angular/core';
import {Http} from '@angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';

@Injectable()
export class GitHubService {    
    private _baseUrl = "https://api.github.com/users/";
    
    constructor(private _http: Http){}
    
    getUser(username){
        return this._http.get(this._baseUrl + username)
            .map(res => res.json());
    }
    
    getFollowers(username){
        return this._http.get(this._baseUrl + username + "/followers")
            .map(res => res.json());
    }

}

github-profile.component.ts

import {Component, OnInit} from '@angular/core';
import {HTTP_PROVIDERS} from '@angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/forkJoin';

import {GitHubService} from './github.service';

@Component({
    selector: 'github-profile',
    styles: [
        `
            .avatar {
                width: 100;
                height: 100;
                border-radius: 100%;
            }
        `
    ],
    template: `
        <i *ngIf="isLoading" class="fa fa-spinner fa-spin fa-3x"></i>
        <h2>@{{ user.login }}</h2>
        <img class="avatar" src="{{ user.avatar_url }}">
        
        <h3>Followers</h3>
        <div *ngFor="#follower of followers" class="media">
            <div class="media-left">
                <a href="#">
                <img class="media-object avatar" src="{{ follower.avatar_url }}" alt="...">
                </a>
            </div>
            <div class="media-body">
                <h4 class="media-heading">{{ follower.login }}</h4>
            </div>
        </div>        
    `,
    providers: [HTTP_PROVIDERS, GitHubService]
})
export class GitHubProfileComponent implements OnInit {
    isLoading = true;
    username = "octocat";
    user = {}; 
    followers = [];
    
    constructor(private _gitHubService: GitHubService){        
    }
    
    ngOnInit(){
        Observable.forkJoin(
            this._gitHubService.getUser(this.username), 
            this._gitHubService.getFollowers(this.username)
        )
        .subscribe(
            res => {
                this.user = res[0];
                this.followers = res[1];
            }, 
            null, 
            () => { this.isLoading = false; })
    }

}

No comments:

Post a Comment