Angular CRUD Example

By Arvind Rai, July 02, 2019
This page will walk through Angular CRUD example using HttpClient class. HttpClient is an injectable class to make HTTP requests. CRUD operation is create, read, update and delete. HttpClient class has methods to make HTTP calls such as HttpClient.post will make HTTP POST request, HttpClient.put will make HTTP put request, HttpClient.get will make HTTP GET request and HttpClient.delete will make HTTP DELETE request etc. All HttpClient methods construct Observable instance and make HTTP requests when they are subscribed.
On this page we will provide CRUD example using Angular in-memory web API. Now find the complete example step-by-step.

Technologies Used

Find the technologies being used in our example.
1. Angular 8.0.3
2. TypeScript 3.4.3
3. Node.js 12.5.0
4. Angular CLI 8.0.6
5. Angular In-Memory Web API 0.8.0

Angular HttpClient

HttpClient is smaller, easier and powerful library for making HTTP requests. HttpClient is an injectable class. For any request it returns Observable instance. It has following methods to perform HTTP requests.
post: Performs HTTP POST request.
get: Performs HTTP GET request.
put: Performs HTTP PUT request.
delete: Performs HTTP DELETE request.
patch: Performs HTTP PATCH request.
head: Performs HTTP HEAD request.
options: Performs HTTP OPTIONS request.
request: Performs any type of HTTP request.
jsonp: Performs HTTP JSONP request.

Observable.pipe

RxJS pipe is used to combine functional operators into a chain. pipe is an instance method of Observable as well as a standalone RxJS function. pipe can be used as Observable.pipe or we can use standalone pipe to combine functional operators. pipe accepts operators as arguments such as filter, map, mergeScan etc. with comma separated and execute them in a sequence they are passed in as arguments and finally returns Observable instance. To get the result we need to subscribe the final Observable response. Find the sample code.
of(1, 2, 3, 4, 5, 6, 7).pipe(
    filter(n => n % 2 === 1),
    map(n => n + 10)
)
.subscribe(result => console.log(result)); 
Output will be 11, 13, 15, 17.

CRUD Operation using HttpClient

We will perform CREATE, READ, UPDATE and DELETE (CRUD) operation using HttpClient. We will perform
1. CREATE operation using HttpClient.post method.
2. READ operation using HttpClient.get method.
3. UPDATE operation using HttpClient.put method.
4. DELETE operation using HttpClient.delete method.

The print screen of our application for CRUD operation will be as follows.
Angular CRUD Example
Now we will discuss CRUD using HttpClient step by step.

1. Import HttpClientModule

To use HttpClient class, we need to import HttpClientModule in application module. HttpClientModule is from @angular/common/http library.
app.module.ts
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  imports: [     
        ---
	HttpClientModule
  ],
  ------
})
export class AppModule { } 

2. Inject HttpClient

HttpClient is injectable and we can get its instance using constructor in a service class.
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
    providedIn: 'root'
})
export class ArticleService {
    constructor(private http: HttpClient) { }
    ------
} 

3. Create

We will perform create operation using Angular HttpClient.post() method. HttpClient.post() constructs an Observable instance and performs HTTP POST operation when it is subscribed. Its syntax is as follows.
post(url, body, options): Observable<any> 
The description of parameters is given as below.
url: This is the REST web service URL to create article.
body: This is the object that will be passed over HTTP request. In our example we will create an Angular class as Article and pass its instance to body parameter.
options: We can pass options such as headers, parameters etc. This argument is optional.

HttpClient.post() returns instance of Observable which is a representation of any set of values over any amount of time.

Find the attributes that can be passed as options argument.
headers: Defines HttpHeaders for http POST request.
observe: Defines whether we want complete response or body only or events only.
params: Defines parameters in URL.
reportProgress: Defines whether we want progress report or not.
responseType: Defines response type such as arraybuffer, blob, json and text.
withCredentials: Defines whether we want to pass credentials or not.

Code
Find the code to create the article.
createArticle(article: Article): Observable<number> {
	let httpHeaders = new HttpHeaders({
		'Content-Type': 'application/json'
	});
	return this.http.post<Article>(this.articleUrl + "/" + article.id, article, {
		headers: httpHeaders,
		observe: 'response'
	}
	).pipe(
		map(res => res.status),
		catchError(this.handleError)
	);
} 
We are passing Article object to create an article and returning Observable instance with status code.

4. Read

We will perform read operation using Angular HttpClient.get() method. HttpClient.get() constructs an Observable instance and performs HTTP GET operation when it is subscribed. Find its syntax.
get(url, options): Observable<any> 
url: This is the REST web service URL to fetch article.
options: We can pass options such as headers, parameters etc. This argument is optional.

Code
In our demo application we will fetch all articles as well as article by id. Find the code to fetch all articles.
getAllArticles(): Observable<Article[]> {
	return this.http.get<Article[]>(this.articleUrl).pipe(
		tap(articles => console.log("Number of articles: " + articles.length)),
		catchError(this.handleError)
	);
} 
Find the code to fetch article by id.
getArticleById(articleId: string): Observable<Article> {
	return this.http.get<Article>(this.articleUrl + "/" + articleId).pipe(
		tap(article => console.log(article.title + " " + article.category)),
		catchError(this.handleError)
	);
} 
In the above code, HttpClient.get() returns Observable instance and when it is subscribed, it will perform HTTP GET operation and returns response.

5. Update

We will perform update operation using Angular HttpClient.put() method. HttpClient.put() constructs an Observable instance and performs HTTP PUT operation when it is subscribed. Find its syntax.
put(url, body, options): Observable<any> 
Find the description of parameters.
url: This is the URL to update article.
body: This is the object that will be passed over HTTP request.
options: We can pass options such as headers, parameters etc. This argument is optional.

Code
Find the code to update the article.
updateArticle(article: Article): Observable<number> {
	let httpHeaders = new HttpHeaders({
		'Content-Type': 'application/json'
	});
	return this.http.put<Article>(this.articleUrl + "/" + article.id, article, {
		headers: httpHeaders,
		observe: 'response'
	}
	).pipe(
		map(res => res.status),
		catchError(this.handleError)
	);
} 
In our Angular application we have created Article object to update for an article id and we are passing its instance to HttpClient.put() method. The article will be updated for that article id.

6. Delete

We will perform delete operation using Angular HttpClient.delete() method. HttpClient.delete() constructs an Observable instance and performs HTTP DELETE operation when it is subscribed. Find its syntax.
delete(url, options): Observable<any> 
Find the description of the parameters.
url: This is the URL to delete article.
options: We can pass options such as headers, parameters etc. This argument is optional.

Code
Find the code to delete article by id.
deleteArticleById(articleId: string): Observable<number> {
	return this.http.delete<number>(this.articleUrl + "/" + articleId).pipe(
		tap(status => console.log("status: " + status)),
		catchError(this.handleError)
	);
} 
In the path parameter we are passing article id to delete the article.

Install Angular In-Memory Web API

In our example we are using in-memory web API for CRUD operation. To use it in our angular application we need to follow below steps.
Step-1: To install angular-in-memory-web-api, run below command from root folder of the project.
npm install angular-in-memory-web-api@0.8.0 --save 
Step-2: Create a class implementing InMemoryDbService interface. In our example we are creating an in-memory DB for articles.
test-data.ts
import { InMemoryDbService } from 'angular-in-memory-web-api';

export class TestData implements InMemoryDbService {
  createDb() {
    let articleDetails = [
      { id: 101, title: 'Angular by Krishna', category: 'Angular' },
      { id: 102, title: 'Core Java by Vishnu', category: 'Java' },
      { id: 103, title: 'NgRx by Rama', category: 'Angular' }
    ];
    return { articles: articleDetails };
  }
} 
To interact with above DB, URL will be /api/articles .
Step-3: Before using in-memory web API, we need to configure our above class in application module as following.
app.module.ts
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { TestData } from './test-data';

@NgModule({
  imports: [     
      ------
      InMemoryWebApiModule.forRoot(TestData)
  ],
  ------
})
export class AppModule { } 
Step-4: For CRUD operation we need to use following URLs.
1. GET /articles : Fetches all articles.
2. GET /articles/101 : Fetches article by id.
3. POST /articles : Create article.
4. PUT /articles : Update article by id.
5. DELETE /articles/101 : Delete article by id.

Complete Example

Find the project structure of our demo application.
my-app
|
|--src
|   |
|   |--app 
|   |   |
|   |   |--article.component.ts
|   |   |--article.service.ts
|   |   |--article.ts
|   |   |--article.component.html
|   |   |--article.component.css
|   |   |
|   |   |--app.component.ts
|   |   |--app.module.ts 
|   |   |
|   |   |--test-data.ts
|   | 
|   |--assets
|   |   |
|   |   |--images
|   |   |    |
|   |   |    |--loading.gif      
|   |   |
|   |   
|   |--main.ts
|   |--index.html
|   |--styles.css
|
|--node_modules
|--package.json 
Now find the complete code.
article.ts
export class Article {
    id: number;
    title: string;
    category: string;
} 
article.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { map, catchError, tap } from 'rxjs/operators';

import { Article } from './article';

@Injectable({
    providedIn: 'root'
})
export class ArticleService {
    //URL for CRUD operations
    articleUrl = "/api/articles";
    //Create constructor to get Http instance
    constructor(private http: HttpClient) { }
    //Fetch all articles
    getAllArticles(): Observable<Article[]> {
        return this.http.get<Article[]>(this.articleUrl).pipe(
            tap(articles => console.log("Number of articles: " + articles.length)),
            catchError(this.handleError)
        );
    }
    //Create article
    createArticle(article: Article): Observable<number> {
        let httpHeaders = new HttpHeaders({
            'Content-Type': 'application/json'
        });
        return this.http.post<Article>(this.articleUrl + "/" + article.id, article, {
            headers: httpHeaders,
            observe: 'response'
        }
        ).pipe(
            map(res => res.status),
            catchError(this.handleError)
        );
    }
    //Fetch article by id
    getArticleById(articleId: string): Observable<Article> {
        return this.http.get<Article>(this.articleUrl + "/" + articleId).pipe(
            tap(article => console.log(article.title + " " + article.category)),
            catchError(this.handleError)
        );
    }
    //Update article
    updateArticle(article: Article): Observable<number> {
        let httpHeaders = new HttpHeaders({
            'Content-Type': 'application/json'
        });
        return this.http.put<Article>(this.articleUrl + "/" + article.id, article, {
            headers: httpHeaders,
            observe: 'response'
        }
        ).pipe(
            map(res => res.status),
            catchError(this.handleError)
        );
    }
    //Delete article	
    deleteArticleById(articleId: string): Observable<number> {
        return this.http.delete<number>(this.articleUrl + "/" + articleId).pipe(
            tap(status => console.log("status: " + status)),
            catchError(this.handleError)
        );
    }
    private handleError(error: any) {
        console.error(error);
        return throwError(error);
    }
}
article.component.ts
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';

import { ArticleService } from './article.service';
import { Article } from './article';

@Component({
	selector: 'app-article',
	templateUrl: './article.component.html',
	styleUrls: ['./article.component.css']
})
export class ArticleComponent implements OnInit {
	//Component properties
	allArticles: Article[];
	statusCode: number;
	requestProcessing = false;
	articleIdToUpdate = null;
	processValidation = false;
	//Create form
	articleForm = new FormGroup({
		title: new FormControl('', Validators.required),
		category: new FormControl('', Validators.required)
	});
	//Create constructor to get service instance
	constructor(private articleService: ArticleService) {
	}
	//Create ngOnInit() and and load articles
	ngOnInit(): void {
		this.getAllArticles();
	}
	//Fetch all articles
	getAllArticles() {
		this.articleService.getAllArticles()
			.subscribe(
				data => this.allArticles = data,
				errorCode => this.statusCode = errorCode);
	}
	//Handle create and update article
	onArticleFormSubmit() {
		this.processValidation = true;
		if (this.articleForm.invalid) {
			return; //Validation failed, exit from method.
		}
		//Form is valid, now perform create or update
		this.preProcessConfigurations();
		let article = this.articleForm.value;
		if (this.articleIdToUpdate === null) {
			//Generate article id then create article
			this.articleService.getAllArticles()
				.subscribe(articles => {
					//Generate article id (logic is for demo)	 
					let maxIndex = articles.length - 1;
					let articleWithMaxIndex = articles[maxIndex];
					let articleId = articleWithMaxIndex.id + 1;
					article.id = articleId;

					//Create article
					this.articleService.createArticle(article)
						.subscribe(statusCode => {
							//Expecting success code 201 from server
							this.statusCode = statusCode;
							this.getAllArticles();
							this.backToCreateArticle();
						},
							errorCode => this.statusCode = errorCode
						);
				});
		} else {
			//Handle update article
			article.id = this.articleIdToUpdate;
			this.articleService.updateArticle(article)
				.subscribe(statusCode => {
					//this.statusCode = statusCode;
					//Expecting success code 204 from server
					this.statusCode = 200;
					this.getAllArticles();
					this.backToCreateArticle();
				},
					errorCode => this.statusCode = errorCode);
		}
	}
	//Load article by id to edit
	loadArticleToEdit(articleId: string) {
		this.preProcessConfigurations();
		this.articleService.getArticleById(articleId)
			.subscribe(article => {
				this.articleIdToUpdate = article.id;
				this.articleForm.setValue({ title: article.title, category: article.category });
				this.processValidation = true;
				this.requestProcessing = false;
			},
				errorCode => this.statusCode = errorCode);
	}
	//Delete article
	deleteArticle(articleId: string) {
		this.preProcessConfigurations();
		this.articleService.deleteArticleById(articleId)
			.subscribe(successCode => {
				//this.statusCode = successCode;
				//Expecting success code 204 from server
				this.statusCode = 204;
				this.getAllArticles();
				this.backToCreateArticle();
			},
				errorCode => this.statusCode = errorCode);
	}
	//Perform preliminary processing configurations
	preProcessConfigurations() {
		this.statusCode = null;
		this.requestProcessing = true;
	}
	//Go back from update to create
	backToCreateArticle() {
		this.articleIdToUpdate = null;
		this.articleForm.reset();
		this.processValidation = false;
	}
} 
article.component.html
<h1>Angular CRUD Example</h1>
<h3 *ngIf="articleIdToUpdate; else create">
  Update Article for Id: {{articleIdToUpdate}}
</h3>
<ng-template #create>
  <h3> Create New Article </h3>
</ng-template>
<div>
  <form [formGroup]="articleForm" (ngSubmit)="onArticleFormSubmit()">
    <table>
      <tr>
        <td>Enter Title</td>
        <td>
          <input formControlName="title">
          <label *ngIf="articleForm.get('title').invalid && processValidation" class="error"> Title is required. </label>
        </td>
      </tr>
      <tr>
        <td>Enter Category</td>
        <td>
          <input formControlName="category">
          <label *ngIf="articleForm.get('category').invalid && processValidation" class="error"> Category is required. </label>
        </td>
      </tr>
      <tr>
        <td colspan="2">
          <button *ngIf="!articleIdToUpdate">CREATE</button>
          <button *ngIf="articleIdToUpdate">UPDATE</button>
          <button (click)="backToCreateArticle()" *ngIf="articleIdToUpdate">Go Back</button>
        </td>
      </tr>
    </table>
  </form>
  <br/>
  <div *ngIf="statusCode; else processing">
    <div *ngIf="statusCode === 201" class="success">
      Article added successfully.
    </div>
    <div *ngIf="statusCode === 200" class="success">
      Article updated successfully.
    </div>
    <div *ngIf="statusCode === 204" class="success">
      Article deleted successfully.
    </div>
    <div *ngIf="statusCode === 500" class="error">
      Internal Server Error.
    </div>
  </div>
  <ng-template #processing>
    <img *ngIf="requestProcessing" src="assets/images/loading.gif">
  </ng-template>
</div>
<h3>Article Details</h3>
<table>
  <tr>
    <th> Id</th>
    <th>Title</th>
    <th>Category</th>
    <th></th>
    <th></th>
  </tr>
  <tr *ngFor="let article of allArticles">
    <td>{{article.id}}</td>
    <td>{{article.title}}</td>
    <td>{{article.category}}</td>
    <td>
      <button type="button" (click)="loadArticleToEdit(article.id)">Edit</button>
    </td>
    <td>
      <button type="button" (click)="deleteArticle(article.id)">Delete</button>
    </td>
  </tr>
</table> 
article.component.css
h1 {
    font-size: 2.0em;
    margin: 20px 0 0 0;
    font-weight: 400;   
}
h3 { 
    color: blue;
}
table {
    border-collapse: collapse;
}
table, th, td {
    border: 1px solid black;
    font-size:17px;
}
input {
    width: 225px;
    margin: 8px 0;
    background-color: #dfdfdf;
    font-size:17px;
}
button {
    background-color: #008CBA;
    color: white;
}
.error{
    color: red;
    font-size: 20px;
}
.success{
    color: green;
    font-size: 20px;
} 
app.component.ts
import { Component } from '@angular/core';

@Component({
   selector: 'app-root',
   template: `
		<app-article></app-article>
             `
})
export class AppComponent { 
} 
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';
import { ArticleComponent } from './article.component';

//For InMemory testing
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { TestData } from './test-data';

@NgModule({
      imports: [
            BrowserModule,
            HttpClientModule,
            ReactiveFormsModule,
            InMemoryWebApiModule.forRoot(TestData)
      ],
      declarations: [
            AppComponent,
            ArticleComponent
      ],
      providers: [],
      bootstrap: [
            AppComponent
      ]
})
export class AppModule { } 

Run Application

To run the application, find the steps.
1. Download source code using download link given below on this page.
2. Use downloaded src in your Angular CLI application. To install Angular CLI, find the link.
3. Install angular-in-memory-web-api@0.8.0
4. Run ng serve using command prompt.
5. Access the URL http://localhost:4200

References

Angular Doc: HttpClient
HttpClient Example

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us