As I said previously, I am starting a demo series of CRUD (Create, read, update, and delete) operations in Angular2. This is part two of that series. In case you missed part one, “How to Create RESTful API using Node.js and MySQL", you can read it from here.
In this second part of the tutorial, I am going to cover the following topics:
- Fetching JSON data from URL
- Filter pipe
- Introduction to HTTP module
- Services
- Conditionally apply CSS class and more
At the end of the article, you can find the link to the source code on Github. So, feel free to play with the code yourself.
In Part One, we have already created a table and named it as TASK which has three columns: Id, Title, and Status. Also, we created Web API. Now, let’s start with fetching the data in Angular2.(Note I am using Angular2 CLI throughout the demo).
Here is the list of a few commands which can be used with Angular-CLI.
Create new component
Command
ng g c "name of the component"
Example
ng g c demo
Explanation
Here, ng stands for Angular, g stands for generate, and c stands for component.
Create new component but not the directory (inside the directory )
Command
ng g c "name of the component" –flat
Example
ng g c demo1 –flat
–flat will not create new directory
Create component with inline CSS and inline HTML
Command
ng g c "name of the component" –flat -is -it
Example
ng g c demo1 –flat -is -it
-is stands for Inline Style
-it stands for Inline template
Deleting Component
Command
ng destroy component "name of the component"
Create Service
Command
ng g s data
Explanation
s stands for service
Create Class Command
ng g cl "name of class"
Example
ng g cl demo
Explanation
cl stands for class
Create custom pipe
Command
ng g p "name of pipe"
Example
ng g p power
Explanation
p stands for pipe
Creating data structure/Class
- cmd > ng g cl tasks[code language = ”typescript”]
- export class Task {
- constructor(public Id: String, public Title: String, public Status: String) {}
- }
- [/code]
So, it will generate one class for us. Now, inside the class, create three properties Id,Title and Status, so that now the object of Task class has 3 properties.
Creating Service
cmd>ng g s taskdata First, navigate to shared folder, then write the above code to generate service.
What are services?
We can say, services mean don’t repeat yourself (Dry)!
Now, what does it mean?
Let’s say for example, we require one function which can be used by more than one components. Then, what happens is that we just need to write the same code again and again for each component. When we want to change some logic in function, then we need to change it on each and every component.
This is why, instead of doing this, we simply create a service in which we can write the code once that can be used by as many components as we want by simply injecting the service Instance. In other languages, services keeps our function and logic centralized.
In general, our service can perform the following tasks:
- Communicate with database.
- Communicate with components /classes.
- Some other business logic which is accessible from various places of our application.
- [code language = ”typescript”]
- public url: string = "https://localhost:3000/Tasks/";
- getAllTasks() {
- return this._http.get(this.url).map((response: Response) => response.json());
- }
- [/code]
The above function will return all the tasks retrieved from the database.
Here, first we need to inject the _http object from @angular/http. Then, we can call out Web API using _http.get method.
The Map function can be imported from the rxjs/Rx. It will map the response into JSON format.
- [code language = ”typescript”]
- import {
- Injectable
- } from '@angular/core';
- import {
- Task
- } from '../tasks/task';
- import {
- Http,
- Headers,
- Response,
- RequestOptions
- } from '@angular/http';
- import 'rxjs/Rx';
- @Injectable()
- export class TaskdataService {
- public url: string = "https://rkdemotask.herokuapp.com/Tasks/";
- constructor(private _http: Http) {}
- getAllTasks() {
- return this._http.get(this.url).map((response: Response) => response.json());
- }
- deleteTask(item: Task) {
- let headers = new Headers({
- 'Content-Type': 'application/json'
- });
- let options = new RequestOptions({
- headers: headers
- });
- return this._http.delete(this.url + item.Id, options).map((response: Response) => response.json());
- }
- addTask(item: Task) {
- let body = JSON.stringify(item);
- let headers = new Headers({
- 'Content-Type': 'application/json'
- });
- let options = new RequestOptions({
- headers: headers
- });
- return this._http.post(this.url, body, options).map((response: Response) => response.json());
- }
- getTaskId(id: any) {
- return this._http.get(this.url + id).map((response: Response) => response.json());
- }
- editTask(item: Task) {
- let body = JSON.stringify(item);
- let headers = new Headers({
- 'Content-Type': 'application/json'
- });
- let options = new RequestOptions({
- headers: headers
- });
- return this._http.put(this.url + item.Id, body, options).map((response: Response) => response.json());
- }
- }
- [code]
The above service contains all methods for create, read, update, and delete. Also, we have imported the Task class here. Http, Headers, Response, RequestOptions can be imported from @angular/http, as shown above.
Note - We need to provide the service inside app.module.ts in order to use it in our application.
- [code language = ”typescript”]
- import {
- TaskdataService
- } from './shared/taskdata.service';
- providers: [TaskdataService], [/code]
Creating Component
So far, we have created class and service. Now, it’s time for component to display the data.
cmd>ng g c tasks
As I am using Angular2-CLI, it will create four files for us.
- tasks.component.css
- tasks.component.html
- tasks.component.ts
- tasks.component.spec.ts
In this article, I am not going to talk about testing, so I removed tasks.component.spec.ts file.
Angular 2 comes with global declaration concept. So, whenever we are creating a component, we need to declare it in app.module.ts, inside the declaration array. But, as we are using Angular-CLI, it will be done automatically by the system, as shown below.
- [code language = ”typescript”]
- import {
- TasksComponent
- } from './tasks/tasks.component';
- @NgModule({
- declarations: [
- AppComponent,
- TasksComponent
- ],
- [/code]
Now, the component is divided into two portions - .html and .ts. Let's create .ts first.
Tasks.component.ts - [code language = ”typescript”]
- import {
- Component,
- OnInit
- } from '@angular/core';
- import {
- Task
- } from './task';
- import {
- TaskdataService
- } from '../shared/taskdata.service';
- import {
- Router
- } from '@angular/router';
- @Component({
- selector: 'app-tasks',
- templateUrl: './tasks.component.html',
- styleUrls: ['./tasks.component.css']
- })
- export class TasksComponent implements OnInit {
- allTasks: Task[] = [];
- constructor(private _datatask: TaskdataService) {}
- ngOnInit() {
- this._datatask.getAllTasks().subscribe(
- (data: Task[]) => {
- this.allTasks = data;
- });
- }
- }
- [/code].
TypeScript file can be divide into 3 sections -
- imports section - contains all the library files used in component. Like task, taskdata.service,etc.
- component metadata - contains the metadata like selector, templateurl, styleurl and more.
- class - contains all the logic.
So, in our example -
- First, create the array named allTasks which is the type of task.
- Then, inject the taskdataservice inside the constructor and create the instance of our service.
- And then finally, call getAllTasks method of our service inside the ngOnInIt event that is a life-cycle hook called by Angular2 for indicating that Angular is done creating the component.
So now, we are good to go for displaying data on our .html. To display the data on HTML, I am using string interpolation method - remember this {{ }}. You can find more about data bindings here.
tasks.component.html
- [code language = ”html”] < div class = "container" > < div class = "row" > < div[hidden] = "allTasks.length>0"
- class = "progress" > < div class = "progress-bar progress-bar-striped active"
- role = "progressbar"
- aria - valuenow = "45"
- aria - valuemin = "0"
- aria - valuemax = "100"
- style = "width: 45%" > < span class = "sr-only" > 45 % Complete < /span> < /div> < /div> < div class = "row" > < table class = "table" > < thead > < th > Id < /th> < th > Title < /th> < th > Status < /th> < /thead> < tr * ngFor = "let item of allTasks " > < td > {
- {
- item.Id
- }
- } < /td> < td > {
- {
- item.Title
- }
- } < /td> < td > {
- {
- item.Status
- }
- } < /td> < /tr> < /table> < /div> < /div> [/code]
Output Now, you all are wondering by seeing the output that the color of status is changing depending on the values ‘done’ and ‘pending’. It is very simple to assign runtime CSS class to any element of HTML, conditionally. So now, let’s see how we can do so.
First, I am creating two CSS classes named as .donestatus and .pendingstatus.
- [code language = ”css”].donestatus {
- color: blue;
- }.pendingstatus {
- color: red;
- }
- [/code]
Syntax
[ngClass]="{cssClass: expression}"
We can use [ngClass] with property binding, as shown below. It will check if Status=’done’, then apply .donestatus css class; otherwise, it will apply .pendingstatus css class. Isn’t it easy?
- [code language = ”html”] < tr * ngFor = "let item of (allTasks |filter:input1.value)" > < td > {
- {
- item.Id
- }
- } < /td> < td > {
- {
- item.Title
- }
- } < /td> < td > < span[ngClass] = "{'donestatus': item.Status=='done','pendingstatus': item.Status=='pending'}" > {
- {
- item.Status
- }
- } < /span></td > < /tr> [/code]
Creating filter pipe
If you don’t know what pipe is? You don’t need to worry about that, because I had already described what pipes are in my previous article. You can read it
here.
cmd>ng g p filter
Note - To use this pipe anywhere in the application, we must declare the pipe inside app.module.ts, same as what we did with components.
- [code language = ”typescript”]
- import {
- FilterPipe
- } from './shared/filter.pipe';
- @NgModule({
- declarations: [
- AppComponent,
- FilterPipe
- ],
- })[/code]
Filter.pipe.ts - [code language = ”typescript”]
- import {
- Pipe,
- PipeTransform
- } from '@angular/core';
- @Pipe({
- name: 'filter'
- })
- export class FilterPipe implements PipeTransform {
- transform(value: any[], arg: any) {
- return value.filter(item => item.Title.startsWith(arg));
- }
- }
- [/code]
So in the above example, I have created transform function which takes two parameters - array (of type task) and arg ( the search term). I have performed a simple search filter operation on an array.
So everything is done now. Should we call the filter pipe on our task.component.html?
Yes, let’s call it. As I have already declared pipe inside the app.module.ts file, there is no need to import it again on component.
Final task.component.html will look like the following, after applying the filter.
tasks.component.html - [code language = ”html”] < input type = "text" (keyup) = "0"#
- input1 class = "form-control"
- placeholder = "Search for..." > < tr * ngFor = "let item of (allTasks |filter:input1.value)" > [/code][code language=”html”] < div class = "container" > < div class = "row" > < div[hidden] = "allTasks.length>0"
- class = "progress" > < div class = "progress-bar progress-bar-striped active"
- role = "progressbar"
- aria - valuenow = "45"
- aria - valuemin = "0"
- aria - valuemax = "100"
- style = "width: 45%" > < span class = "sr-only" > 45 % Complete < /span> < /div> < /div> < div class = "input-group" > < span class = "input-group-btn" > < button class = "btn btn-default"
- type = "button" > < span class = "glyphicon glyphicon-search" > < /span></button > < /span> < input type = "text" (keyup) = "0"#
- input1 class = "form-control"
- placeholder = "Search for..." > < /div> < /div> < br / > < div class = "row" > < table class = "table" > < thead > < th > Id < /th> < th > Title < /th> < th > Status < /th> < /thead> < tr * ngFor = "let item of (allTasks |filter:input1.value)" > < td > {
- {
- item.Id
- }
- } < /td> < td > {
- {
- item.Title
- }
- } < /td> < td > < span[ngClass] = "{'donestatus': item.Status=='done','pendingstatus': item.Status=='pending'}" > {
- {
- item.Status
- }
- } < /span></td > < /tr> < /table> < /div> < /div> [/code]
What I did is simply add one input box and created a (keyup) event so that when user inputs data, it filters the below table. I also used template binding.
- [code language = ”html”] < input type = "text" (keyup) = "0"#
- input1 class = "form-control"
- placeholder = "Search for..." > < tr * ngFor = "let item of (allTasks |filter:input1.value)" > [/code]
Filter will take allTasks array as first argument and input1.value as second argument for that transform function inside the filter.pipe.ts.
Output
Summary
Angular 2 is simply awesome. Isn’t it?
We covered a lot in this tutorial. Let’s just summarize it.
- Angular-CLI
- Created class
- Services
- Components
- Run time css class
- Filter pipe and more…
There is a lot more to come in the next part of the tutorial (routing, insert, validations, update, and delete). So, stay tuned for more. I will provide the Github link of the demo application in the last part of this tutorial.