This is a 4 series to help you kickstart your coding in angular 4.

  1. Code Angular – Basic Series- Part 1
  2. Code Angular – Basic Series- Part 2
  3. Code Angular – Basic Series- Part 3
  4. Code Angular – Basic Series- Part 4

In chapter 3, we explore,

  1. how you create an Api Service to perform CRUD to server side
  2. how you can create a universal loading indicator
  3. how you can lazy load your modules for great app experiences

The final plunk result output with its code.


1) How you can create a service that connect to your backend server for crud operation like get, put,post,delete?

In a high level, we want to achieve something like this.

 

Let’s start!

Open file app/app.module.ts and import our new service ApiService.

 
import { ApiService } from './api.service';
...
..
.
 @NgModule({
  imports: [ ... ],
  declarations: [.. ],
  providers: [  ApiService ],
  bootstrap: [ ...]
})
...
..
. 

Create the file app/api.service.ts like how we did earlier for app/data.service.ts . Since we will do a connectivity to host, import the following libraries as below.

 
import { Injectable } from '@angular/core';   
import { Headers, Http, Response } from '@angular/http';
import 'rxjs/Rx';
import 'rxjs/add/operator/toPromise'; 

@Injectable()
export class ApiService { ... }

Our next step is we need create common property attributes commonly use in REST api services.

 
export class ApiService { 
 
    private baseUrlPath = 'https://localhost:3006/Api';
    private servicePath= '';//eg. /listing or /details or /detail/$id
    private headers = new Headers({ 'Content-Type': 'application/json' });

    private bodyRequest = {};
    private bodyResponse = {};

    //getter and setters for each above
 }

Define baseUrlPath for the base domain name of the api.
Define servicePath for the specific uri name of the api service url.
Define headers for the request ajax header we will send from host API.
Define bodyRequest for the request ajax body we will send from server.
Define bodyResponse for the request ajax body we will receive from server.

After we had done our definition of common attributes with its getter and setter methods,
we look into how actually create a generic public method to invoke the GET,POST,PUT,DELETE operation typical in a REST API.

 
    getData(): Promise {  } //GET -list all
    private handleError(error: any): Promise { ...  } //error handler
    getDataBasedOnId(id: number): Promise {... }    //GET- list details
    createData(requestObj: string): Promise { ...  }  //POST -add new record
    updateData(requestObj: any): Promise {  ... } //PUT - update current record
    deleteData(requestObj: any): Promise { ... } //DELET - remove current record

The GET operations. We import the http instances by @angular.

 
 getData(): Promise < any[] > {  
    return this.http.get(`${this.baseUrlPath}${this.servicePath}`)
        .toPromise()
        .then((response) => { 
            this.bodyResponse = response.json() as any[];
            return this.bodyResponse;
        })
        .catch((e) => { console.log(e); this.handleError(e); return null; });
}

getDataBasedOnId(id: number): Promise < any > {
    const url = `${this.baseUrlPath}/${id}`;
    return this.http.get(url)
        .toPromise()
        .then(response => { this.bodyResponse = response.json().data; return response.json().data; })
        .catch(this.handleError);
}

 private handleError(error: any): Promise < any > { 
    if(this) {  this.bodyResponse = error;   } 
   return null;
}

The POST operation.

  
    createData(requestObj: string): Promise {
        return this.http
            .post(this.baseUrlPath, JSON.stringify(requestObj), { headers: this.headers })
            .toPromise()
            .then(response => { this.bodyResponse = response.json().data; 
               return response.json().data;  }).catch(this.handleError); 
    } 

The PUT operation.

   
    updateData(requestObj: any): Promise {
        const url = `${this.baseUrlPath}${this.servicePath}`;
        return this.http
            .put(url, JSON.stringify(requestObj), { headers: this.headers })
            .toPromise()
            .then(() => requestObj)
            .catch(this.handleError);
    } 

The DELETE operation.

   
    deleteData(requestObj: any): Promise {
        const url = `${this.baseUrlPath}${this.servicePath}`;
        return this.http.delete(url, { headers: this.headers })
            .toPromise()
            .then(() => null)
            .catch(this.handleError);
    }

We defined our ApiService . Now , how we can use it?
Same as before, first import it. second invoke it.

 
import { ApiService } from '../api.service';
...

export class DetailsComponent {
...
    constructor(   private apiService: ApiService   ) { } // import it via DI
...
      
     // invoke it ...
      this.apiService.setServicePath(`/friday/someid`);
      //post
      this.apiService.createData( _fridayActivity )
      .then(response => {  return   _fridayActivity = response || _fridayActivity;    })
      .catch(error => { this.error = error});
      
      //put
      this.apiService.createData( _fridayActivity ).then...catch...

     //delete
      this.apiService.createData( _fridayActivity ).then..catch...

      //get
      this.apiService.getData().then..catch...
      ....
    }
}

It is very simple. Now you have a re-usable service you can share across your component.

Seems like we need something else. How about a loading indicator to block user click or activity until service resolved loading from api host ?

Create an interface file , app/interface/iloader.ts

 
import {Component, Injectable} from '@angular/core' 
export interface ILoader {    isLoading:boolean; }

In our ApiService, we import the interface and create an instance for it with public getter and setter.

  
import { ILoader } from './interface/iloader';
...
export class ApiService { 
public loader: ILoader = { isLoading: false };
showLoader() { this.loader.isLoading = true;  }
hideLoader() {  this.loader.isLoading = false; }
}

The idea is whenever, the service we invoke starts, we show the indicator. When it resolves , we hide it.

  
 getData(): Promise {
      this.showLoader(); //show when started.      
       return this.http.get(`${this.baseUrlPath}${this.servicePath}`)
            .toPromise()
            .then((response) => {
                  this.hideLoader(); //hidden when resolved.      
                   return response;
            })
            .catch((e)=>{this.hideLoader();   return null;});//hidden when resolved.      
}

We managed the data state for indicator here. How about html and display?
We want to make it global, so we modify the bootstrap base html
app/app.component.html

   
     <div id="loadingCanvas" *ngIf="loader.isLoading"></div>
      other html content here...

… and the controller component to link the state to the api states.
app/app.component.ts

   
....
  private loader: ILoader;
....
    constructor(private apiService: ApiService) {
        this.loader = this.apiService.loader;
    }

we should not forget the css too..
Recommending you to use class over id selector, this is just simple demo.
app/app.component.css

   
#loadingCanvas {  
      position:absolute;
      top:0;
      left:0;
      width:100%;
      height:100%;
      z-index:1000;
      background-color:grey;
      opacity: .8;
   }

So now, whenever we invoke the apiservice method, the start state will trigger indicator data state to true and else false.
This state is monitored by the primary app, and will show and hide loading in html based on that indicator.


Let’s explore lazy loading now.

What is it and why should we use it?
Lazy load is when we do not want to load and bundle everything on first time initialization but instead only load on demand when certain user action or event triggered.

Why is it needed?
Image if we have 300 components and we register them into our app.component.ts .
To start first time and initialize would imply user wait very long time and this is a serious impact to the app bundling and performance resource costs.
Furthermore, every components loaded at firsttime will not be necessarily used by our user.

Imagine yourself going to a grocery store with 300 trolleys even when you have not yet started shopping. Your actual experience requirement only need probably a single basket. The ideal way is for you to choose what you need and when you need it only.

Here you will see how to achieve this.
We look in our app/app.module.ts , we should only include 1 bootstrap component.

 
...
//before
   declarations: [  AppComponent ,component1......component1000 ],
...
//after
 declarations: [   AppComponent    ],

Then, we look into
We look in our app/app-routing.module.ts

 
//before:traditional : { path: 'list',  component: ListComponent },
//after:lazyloaded: { path: 'list',  loadChildren: './app/list/list.module#ListModule' },
...
const routes: Routes = [
  { path: '', redirectTo: '/list', pathMatch: 'full' },
  { path: 'list',  loadChildren: './app/list/list.module#ListModule' },
  { path: 'details/:mode/:id',  loadChildren: './app/details/details.module#DetailsModule' }  
];
....

In conventional way, we need import Listcomponent, then bind them in the path. With lazy load approach, we only specify path in loadChildren, and component will not load until path route is triggered.

** Importing too many components can be overhead and overkill to user experience. Knowing how to strike balance is good. In some case, if we import few commonly used components by users in conventional manner, it is helping user experience because already preloaded, without repeating waiting time to load. For example, we have a common header and footer components, preloading them is better idea than lazy load. In another example, we have a rarely accessed module like long written term and conditions, lazy loading is better here then.

To compose a lazyload module, we create a grouped folder,add module,route and components.
app/details/details.module.ts
app/details/details.routes.ts
app/details/details.component.ts
app/details/details.html.ts

and

we create
app/list/delistails.module.ts
app/list/list.routes.ts
app/list/list.component.ts
app/list/list.html.ts

The approach is similar to how we create our app.module.ts and register our app-routing.module.ts but instead we are breaking them down into another module.

Be sure to checkout and refer to plunkr for full implementation.


To continue next:
Code Angular – Basic Series- Part 4


If you like please share this and comment and subscribe. Feel free to ask any questions or corrections too.

Success is no accident. It is hard work, perseverance, learning, studying, sacrifice and most of all, love of what you are doing or learning to do, Pele

Leave a Reply

Your email address will not be published. Required fields are marked *