Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Learn Angular Tutorial - Part 4

5.00/5 (3 votes)
22 Sep 2017CPOL13 min read 27.2K   466  
Making HTTP calls and creating custom Angular components using Input and Outputs
This is part 4 of Learn Angular tutorial. In this article, we will understand how to make HTTP calls and how to create custom Angular components using Input and Outputs.

Contents

Links to Rest of the Articles

  • In the first part, we look into Node, TypeScript, Module loaders /Bundlers and VS Code
  • In the second article, we create a simple basic Angular application with a screen and we ran through important concepts like components and modules
  • In the third article, we look into implementing SPA and validations
  • In the fourth article, we understand how to make HTTP calls and how to create custom Angular components using Input and Outputs
  • In the fifth part, we cover two labs - one is how to use Jquery with Angular and Lazy routing
  • In the sixth part, we again cover two labs - Pipes and DI using providers

Lab 9: Making HTTP Calls

Importance of Server Side Interaction

HTML user interfaces are dead if there is no server side interaction. Normally in a web application, we would like to send the data entered by end user to the server. On server side, we would have some kind of service which can be created in technologies like Java, C# and so on. The server side technology can save, edit or delete this data in a database.

In simple words, we need to understand how to make HTTP calls from Angular code to a server side technology.

Yes, this is a pure Angular article.

I intend to keep this article as a pure Angular article. So teaching server side technology like ASP.NET MVC, Java services, PHP is out of scope.

So the server side service would be FAKED (Mocked) by using “Angular inmemory Webapi”. Please note this is not a service which you will use for production. It's only for test and development purposes.

In case you want to learn ASP.NET MVC, you can start from this video.

Step 1: Creating a Fake Server Side Service

Even though we have decided that we will not be creating a professional server side service using ASP.NET, Java, etc. but we will still need one. So we will be using a fake service called as “Angular in-memory web api”.

Already, the “Angular inmemory web api” has been installed when we did npm. You can check your “package.json” file for the entry of “Angular inmemory web api”.

Already the “Angular inmemory web api” has been installed when we did npm. You can check your “package.json” file for the entry of “angular inmemory web api”.

So let’s create a folder called as “Api” and in that, let's add “CustomerApi.ts” file and in this file, we will write code which will create a fake customer service.

On this fake service, we will make HTTP calls.

Below is a simple service created using “angular-in-memory” open source. In this service, we have loaded a simple “customers” collection with some sample customer records.

JavaScript
import { InMemoryDbService } from 'angular-in-memory-web-api'
import {Customer} from "../Model/Customer"
export class CustomerApiService implements InMemoryDbService {
  createDb() {
    let customers =[
      { CustomerCode: '1001', CustomerName: 'Shiv' , CustomerAmount :100.23 },
      { CustomerCode: '1002', CustomerName: 'Shiv1' , CustomerAmount :1.23 },
      { CustomerCode: '1003', CustomerName: 'Shiv2' , CustomerAmount :10.23 },
      { CustomerCode: '1004', CustomerName: 'Shiv3' , CustomerAmount :700.23 }
    ]
    return {customers};
  }
}

So now when Angular makes HTTP call, it will hit this in-memory API.

So when you make a HTTP GET, it will return the above four records. When you make a HTTP POST, it will add the data to the in-memory collection.

In other words, we do not need to create a professional server side service using ASP.NET or Java service.

Step 2: Importing HTTP and WebAPI Module into Main Module

The next step is to import “HttpModule” from “angular/http” and in-memory API into main module. Remember module is collection of components. So the “MainModule” has “CustomerComponent” , “SupplierComponent”, “MasterpageComponent” and “WelcomeComponent”.

JavaScript
import { HttpModule} from '@angular/http';
import {CustomerApiService} from "../Api/CustomerApi"

Also in the “NgModule” attribute in imports, we need to specify “HttpModule” and “InMemoryWebApiModule”.

JavaScript
@NgModule({
    imports: [….
        HttpModule, 
        InMemoryWebApiModule.forRoot(CustomerApiService),
             …..],
    declarations: […],
    bootstrap: [….]
})
export class MainModuleLibrary { }

Shiv: Talk about the sequence of the Httpmodule and Angular Webapi.

Where Do We Put the HTTP Call?

The next question comes which is the right place to put HTTP calls?

So if you see the normal architecture of Angular, it is as follows:

  • User interface is binded with the Angular component using bindings ”[()]”.
  • So once end user starts putting data in the UI, the model object (in our case, it’s the customer object) will be loaded and sent to the Customer component.
  • Now customer component has the filled customer object. So the right place to make HTTP call is in the component.

Step 3: Importing HTTP in the Customer Component

So let’s go ahead and import the Angular HTTP inside the Customer component.

JavaScript
import { Http, Response, Headers, RequestOptions } from '@angular/http';

We do not need to create object of HTTP using the new keyword, it will be dependency injected via the constructor. So on the constructor component, we have defined the object injection of HTTP.

JavaScript
constructor(public http:Http){
    }

Step 4: Creating Header and Request Information

When we send HTTP request from client to server or we get response, header information is passed with the request and response. In header information, we have things like content types, status, user agent and so on.

So to create a request, we need to first create a header and using that header, create a request. One of the header information we need to provide is type of content we are sending to server - is it XML, JSON, etc.

Below is how to create a simple request using basic header information.

JavaScript
let headers = new Headers({'Content-Type': 'application/json'});
let options = new RequestOptions({ headers: headers });

Step 5: Making HTTP Calls and Observables

Angular HTTP uses something called as observables. So Angular is an observer and it subscribes to observable like HTTP response. In other words, it's listening to data coming from the server.

So the below code says that we will be making a GET call to “api/customers” URL and when the data comes, we will send the successful data to the “Success” function and when error occurs, we will get it in “Error” function.

JavaScript
var observable = this.http.get("api/customers",  options);
        observable.subscribe(res => this.Success(res),
            res => this.Error(res));

Below is the code of Error and Success function. In “Success” function, we are converting the response to JSON and assigning it to “Customers” collection which is in the component. If we have error, we are displaying it in the browser console.

JavaScript
Error(err) {
        console.debug(err.json());
    }
    Success(res) {
        this.Customers = res.json().data;
    }

Step 6: Creating a Simple Post and Get Call

With all that wisdom we have gathered from Step 4 and Step 5, let's write down two functions, one which will display data and the other which will post data.

Below is a simple “Display” function which makes a HTTP GET call.

JavaScript
Display(){   
        let headers = new Headers({
            'Content-Type': 'application/json'
        });
        let options = new RequestOptions({ headers: headers });
        var observable = this.http.get("api/customers",  options);
        observable.subscribe(res => this.Success(res),
            res => this.Error(res));
    }

As soon as the customer UI is loaded, the customercomponent object will be created. So in the constructor, we have called the “Display” function to load the customers collection.

JavaScript
export class CustomerComponent {
// other code removed for clarity
constructor(public http:Http){
            this.Display();
    }
// other codes removed for clarity
}

Below is simple “Add” function which makes a POST call to the server. In http POST call code below, you can see customer object sent as the third parameter. After the “Add” call, we have made call to “Display” so that we can see the new data added on the server.

JavaScript
Add(){
           let headers = new Headers({
            'Content-Type': 'application/json'
        });
        var cust:any = {};
        cust.CustomerCode = this.CurrentCustomer.CustomerCode;
        cust.CustomerName = this.CurrentCustomer.CustomerName;
        cust.CustomerAmount = this.CurrentCustomer.CustomerAmount;
        let options = new RequestOptions({ headers: headers });
        var observable = this.http.post("api/customers",cust,  options);
        observable.subscribe(res => this.Success1(res),
            res => this.Error(res));
        this.Display();
    }

In the above “Add” function, you can see the below code which creates a fresh lightweight customer object. So why do we need to create this fresh new object?

JavaScript
var cust:any = {};
cust.CustomerCode = this.CurrentCustomer.CustomerCode;
cust.CustomerName = this.CurrentCustomer.CustomerName;
cust.CustomerAmount = this.CurrentCustomer.CustomerAmount;

The current customer object has lot of other things like validations, prototype object, etc. So posting this whole object to the server does not make sense. We just want to send three properties “CustomerCode”, “CustomerAmount” and “CustomerName”.

In other words, we need to create a light weight DTO (Data Transfer Object) which just has those properties.

Step 7: Connecting Components to User Interface

Now that our component is completed, we need to attach the “Add” function to the button using the “click” event of Angular. You can see that the (click) is inside a round bracket, in other words, we are sending something (event click) from UI to the Object.

HTML
<input type="button" 
value="Click" (click)="Add()" [disabled]="!(CurrentCustomer.formGroup.valid)"/>

Also, we need to create a table in which we will use “ngFor” loop and display the customers collection on the HTML UI. In the below code, we have created a temporary object “cust” which loops through the “Customers” collection and inside tag, we are using the expressions ({{cust.CustomerName}}) to display data.

HTML
<table>
    <tr>
        <td>Name</td>
         <td>code</td>
          <td>amount</td>
    </tr>
      <tr *ngFor="let cust of Customers">
        <td>{{cust.CustomerName}}</td>
         <td>{{cust.CustomerCode}}</td>
          <td>{{cust.CustomerAmount}}</td>
    </tr>
</table>

Go ahead and run the application. If you go and add “customer” object you should see the HTTP calls happening and the list getting loaded in the HTML table.

Lab 10: Input, Output and Emitters

Theory

Reusability is one of the most important aspects of development. As Angular is a UI technology, we would like to create UI controls and reuse them in different UI.

For example, in the Customer UI, we have the table grid display. If we want to create grid in other UI, we need to again repeat the “<tr><td>” loop. It would be great if we can create a generic reusable grid control which can be plugged into any UI.

If we want to create a GENERIC reusable grid control, you need to think GENERICALLY, you need to think in terms of INPUTS and OUTPUTS.

So if you are using this grid control with a Customer UI, you get a Customer collection, if you are using a Supplier UI, you will get a supplier collection.

In order to achieve this generic thought process, Angular has provided three things, Input, Output and Event emitters.

Input helps us define the input data to the user control. Output uses event emitters to send data to the UI in which the user control is located.

Planning How the Component Will Look Like

First, let us plan how our grid component will look like. Grid component will be called in main HTML using “<grid-ui></grid-ui>” HTML element. The grid component will have three attributes:

  • grid-columns: This will be an input in which we will specify the columns names of the grid.
  • grid-data: This will again be an input in which we will provide the data to be displayed on the grid.
  • grid-selected: This will be an output from which the selected object will be sent via emitter events to the contained UI.
HTML
<grid-ui  [grid-columns]="In this we will give column names"
    [grid-data]="In this we will give data for grid"
    (grid-selected)="The selected object will be sent in event">
</grid-ui>

Step 1: Import Input, Output and Event Emitter

So first, let us go ahead and add a separate file for grid component code and name it “GridComponent.ts”.

In this file, we will write all the code that we need for Grid component.

The first step is to add necessary components which will bring in Input and Output capabilities. For that, we need to import component, Input, Output and event emitter component from “angular/core”.

JavaScript
import {Component,
        Input,
        Output,
        EventEmitter} from "@angular/core"

Step 2: Creating the Reusable GridComponent Class

As this is a component, we need to decorate the class with “@Component” decorator. The UI for this component will coded in “Grid.html”. You can also see in the below code we defined the selector has “grid-ui”, can you guess why?

If you remember in the planning phase, we had said that the grid can be called by using “<grid-ui>” tag.

JavaScript
@Component({
    selector: "grid-ui",
    templateUrl : "../UI/Grid.html"
})
export class GridComponent {
}

Step 3: Defining Inputs and Output

As this is a grid component, we need data for the grid and column names for the grid. So we have created two array collection one, “gridColumns” (which will have column names) and “gridData” ( to data for the table).

JavaScript
export class GridComponent {
    // This will have columns
    gridColumns: Array<Object> = new Array<Object>();
    // This will have data
    gridData: Array<Object> = new Array<Object>();
}

There are two methods “setGridColumns” and “setGridDataSet” which will help us to set column names and table data to the above defined two variables.

These methods will be decorated by using “@Input” decorators and in this, we will put the names by which these inputs will be invoked while invoking this component.

JavaScript
// The top decorator and import code is removed
// for clarity purpose

export class GridComponent {
// code removed for clarity
    @Input("grid-columns")
    set setgridColumns(_gridColumns: Array<Object>) {
            this.gridColumns = _gridColumns;
        }
    @Input("grid-data")
    set setgridDataSet(_gridData: Array<Object>) {
            this.gridData = _gridData;
        }
}

The names defined in the input decorator will be used as shown below while making call to the component in the main UI.

HTML
<grid-ui  [grid-columns]="In this we will give column names"
    [grid-data]="In this we will give data for grid" >
</grid-ui>

Step 4: Defining Event Emitters

As discussed in this Labs theory section, we will have inputs and outputs. Outputs are again defined by using “@Output” decorator and data is sent via event emitter object.

To define output, we need to use “@Output” decorator as shown in the below code. This decorator is defined over “EventEmitter” object type. You can see that the type is “Object” and not “Customer” or “Supplier” because we want it to be of a generic type. So that we can attach this output with any component type.

HTML
@Output("grid-selected")
    selected: EventEmitter<Object> = new EventEmitter<Object>();

Now when any end user selects a object from the grid, we need to raise event by using the “EventEmitter” object by calling the “emit” method as shown below:

HTML
// Other codes have been removed for clarity purpose.
export class GridComponent {
    @Output("grid-selected")
    selected: EventEmitter<Object> = new EventEmitter<Object>();

    Select(_selected: Object) {
        this.selected.emit(_selected);
    }
}

Below goes the full code of “GridComponent.ts” which we have discussed till now.

HTML
import {Component,
        Input,
        Output,
        EventEmitter} from "@angular/core"

@Component({
    selector: "grid-ui",
    templateUrl : "../UI/Grid.html"
})
export class GridComponent {
    gridColumns: Array<Object> = new Array<Object>();
    // inputs
    gridData: Array<Object> = new Array<Object>();

    @Output("grid-selected")
    selected: EventEmitter<Object> = new EventEmitter<Object>();
    @Input("grid-columns")
    set setgridColumns(_gridColumns: Array<Object>) {
            this.gridColumns = _gridColumns;
        }

    @Input("grid-data")
    set setgridDataSet(_gridData: Array<Object>) {
            this.gridData = _gridData;
        }
   
    Select(_selected: Object) {
        this.selected.emit(_selected);
    }
}

Step 5: Creating UI for the Reusable Component

Also, we need to create UI for the “GridComponent.ts”. Remember if we have an Angular component, we NEED A HTML UI for it.

So in the UI folder, we will add “Grid.html” in which we will write the code of table display.

In the “GridComponent.ts” (refer to Step 4 of this Lab), we have defined input “gridColumns” variable in which we will provide the columns for the grid. So for that, we had made a loop using “*ngFor” which will create the columns “<td>” dynamically.

HTML
<table>   
 <tr>
        <td *ngFor="let col of gridColumns">
            {{col.colName}}
        </td>
    </tr>
</table>

And to display data in the grid, we need to loop through “gridData” variable.

HTML
    {{colObj[col.colName]}}

<a>Select</a>

So the complete code of “Grid.html” looks as shown below:

HTML
<table>
    <tr>
        <td *ngFor="let col of gridColumns">
            {{col.colName}}
        </td>
    </tr>
    <tr *ngFor="let colObj of gridData">
        <td *ngFor="let col of gridColumns">
            {{colObj[col.colName]}}
        </td>
        <td><a [routerLink]="['Customer/Add']" 
        (click)="Select(colObj)">Select</a></td>
    </tr>
</table>

Step 6: Consuming the Component in the Customer UI

So now that our reusable component and its UI is completed, let's call the component in the “Customer.html” UI.

Below is the full proper code which has column names defined in “grid-columns” and in “grid-data”, we have set “Customers” collection. This “Customers” collection object is exposed from the “CustomerComponent” class. This “Customers” collection is that collection which we had created during the “HTTP” call lab. This variable has collection of “Customer” data.

HTML
<grid-ui
      [grid-columns]="[{'colName':'CustomerCode'},
      {'colName':'CustomerName'},{'colName':'CustomerAmount'}]"
    [grid-data]="Customers"
    (grid-selected)="Select($event)"></grid-ui>

Also, we need to ensure that the old “<table>” code is deleted and is replaced with the above “<grid-ui>” input /output tag.

Step 7: Creating Events in the Main Customer Component

If you remember in our "GridComponent", we are emitting event by calling “emit” method. Below is the code snippet for it. Now this event which is emitted needs to caught in the “CustomerComponent” and processed.

JavaScript
export class GridComponent {
    Select(_selected: Object) {
        this.selected.emit(_selected);
    }
}

So in order to catch that event in the main component, we need to create a method in “CustomerComponent” file. So in the customer component typescript file, we will create a “Select” function in which the selected customer will come from the GridComponent and that selected object will be set to “CurrentCustomer” object.

JavaScript
export class CustomerComponent {
Select(_selected:Customer) {
        this.CurrentCustomer.CustomerAmount =_selected.CustomerAmount;
        this.CurrentCustomer.CustomerCode = _selected.CustomerCode;
        this.CurrentCustomer.CustomerName = _selected.CustomerName;
    }
}

Step 8: Defining the Component in the mainmodule

Also, we need to ensure that the “GridComponent” is loaded in the main module. So in the main module, import the “GridComponent” and include the same in the declaration of “NgModule” decorator as shown in the below code:

JavaScript
import { GridComponent }   from '../Component/GridComponent';
@NgModule({
    imports: [RouterModule.forRoot(ApplicationRoutes),
        InMemoryWebApiModule.forRoot(CustomerApiService),
             BrowserModule,ReactiveFormsModule,
             FormsModule,HttpModule],
    declarations: [CustomerComponent,
                MasterPageComponent,
                SupplierComponent,
                WelcomeComponent,
                GridComponent],
    bootstrap: [MasterPageComponent]
})
export class MainModuleLibrary { }

And that’s it! Hit Control + B, run the server and see your reusable grid working.

What's in the Next Article?

In Part 5, we will look into how to do dynamic routing and how to use Jquery in Angular.

For further reading, do watch the below interview preparation videos and step by step video series.

History

  • 22nd September, 2017: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)