Rest API with Angular
Consuming the JSON REST API with Angular HttpClient
Introduction
Angular provides a client HTTP API for Angular applications, the HttpClient
service class in @angular/common/http
.
Before we start I’m assuming you are familiar with routing basics. I have attached a link for a quick overview.
Setup server communication
To use HttpClient, we first need to import HttpClientModule in the root app module
.app/app.module.ts
import { HttpClientModule } from '@angular/common/http';
Inside the @NgModules imports add the HttpClientModule
// import HttpClientModule after BrowserModule.
HttpClientModule,
Consuming the JSON REST API with Angular HttpClient
To do this we need to create an Angular service for encapsulating the code that deals with consuming data from Rest Api server.
A service is a singleton that can be injected by other services and components using the Angular dependency injection.
Components shouldn’t fetch or save data directly and they certainly shouldn’t knowingly present fake data. They should focus on presenting data and delegate data access to a service.
Services are a great way to share information among classes that don’t know each other.
create a service
ng generate service user
or
ng g s user
Create a get request method to fetch data from API
public getUsers(): Observable<any> {
return this.httpClient.get(this.baseUrl);
}
The @Injectable()
decorator marks the class as one that participates in the dependency injection system. It accepts a metadata object for the service.
Class
Create a class to specify the required fields. Creates a new, generic class definition in the given or default project.
ng g class <name> [options]
ng g class User
<name>
is the name of the new class.
add data to the class. Add the name of one of the response from rest API
export class User {
id!: number;
name!: String;
occupation!: String;
email!: String;
bio!: String;
}
Call the API function in the service class from component.ts class.
OnInit
A lifecycle hook that is called after Angular has initialized all data-bound properties of a directive. Define an ngOnInit()
method to handle any additional initialization tasks. A callback method that is invoked immediately after the default change detector has checked the directive’s data-bound properties for the first time, and before any of the view or content children have been checked. It is invoked only once when the directive is instantiated.
Display the users in a table by looping through the elements in users. User details route is handled below in case you have an error, finish the blog before running the code on the browser or you can comment out the section for now.
Hope all goes well.
Get a user by id:
Create a route by Updating the app-routing.module.ts with the code below
import { UserDetailsComponent } from './user-details/user-details.component';const routes: Routes = [
{ path: 'users', component: UserListComponent },
{ path: 'users/:id', component: UserDetailsComponent }
];
Create a method to get user in the service class. Update the service class above.
public getUser(id: number): Observable<Object> {
return this.httpClient.get(`${this.baseUrl}/${id}`);
}
Add a details button in list table.(users-list.component.html)
<th>Action</th>//and its table data<td>
<button (click)="userDetails(user.id)" class='btn btn-info' data- toggle="modal"data-target="#myModal">Details</button>
</td>
Update the user-list.component.ts with the route functionality. When a user taps a button it navigates to the new page with the id of the user.
userDetails(id: number) {
this.router.navigate(['users', id]);
console.log(id);
}
When you click on the details button in users list, it should navigate to a new page with the user id on the browser.
Get data to the new page
Create a form to display data in the new component.html
<h2>Users Details</h2><hr /><div *ngIf="user"> <div>
<label><b>First Name: </b></label> {{user.name}}
</div><div>
<label><b>Email </b></label> {{user.email}}
</div><div>
<label><b>Occupation: </b></label> {{user.email}}
</div><div>
<label><b>Bio: </b></label> {{user.bio}}
</div></div><br><br><button (click)=" usersList()" class="btn btn-primary">Back to User List</button><br>
Call the user details API from the component class
ActivatedRoute
Provides access to information about a route associated with a component that is loaded in an outlet. Use to traverse the RouterState
tree and extract information from nodes.
Improve the UI with bootstrap and material design
npm install --save @angular/material
Update your app.module.ts with the packages you installed
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { UserListComponent } from './user-list/user-list.component';
import { AppRoutingModule } from './app-routing.module';
import { UserDetailsComponent } from './user-details/user-details.component';
import { UpdateUserComponent } from './update-user/update-user.component';
import { FormsModule } from '@angular/forms';
import { AddUserComponent } from './add-user/add-user.component';
import { MatButtonModule } from '@angular/material/button';
import { MatTableModule } from '@angular/material/table';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatPaginatorModule } from '@angular/material/paginator';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';@NgModule({
declarations: [
AppComponent,
UserListComponent,
UserDetailsComponent,
UpdateUserComponent,
AddUserComponent
],imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
FormsModule,
MatButtonModule,
MatTableModule,
MatToolbarModule,
MatPaginatorModule,
NgbModule,
MatProgressSpinnerModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
npm i bootstrap
check if bootstrap is added to your project. open angular.json. You can check inside styles
There are other methods of installing these packages if you encounter an error.
Create a table using material design
update user-list.component.html
//title
<div class=" border border-class">
<h2 class="h2-class">User List</h2>
</div>
///Add button
<button mat-raised-button class="btn btn-info " style="float: right; " (click)="addUser()">Add</button>
<!-- style="float: right; margin:10px; -->
///search button
<div class="col-md-3 " style="margin:10px "> <form>
<input type="text" [(ngModel)]="email" class="form-control " (input)="search()" name="email" placeholder="search email">
</form>
</div>
/// users list table
<div>
<mat-table class="users-table mat-elevation-z8" [dataSource]="users" matSort>
<!-- Name Column -->
<ng-container matColumnDef="name"> <mat-header-cell *matHeaderCellDef>Name</mat-header-cell> <mat-cell *matCellDef="let user ">{{user.name}}</mat-cell> </ng-container> <!-- email Column -->
<ng-container matColumnDef="email"> <mat-header-cell *matHeaderCellDef>Email</mat-header-cell> <mat-cell *matCellDef="let user ">{{user.email}}</mat-cell> </ng-container> <!-- bio Occupation -->
<ng-container matColumnDef="occupation"> <mat-header-cell *matHeaderCellDef>Occupation</mat-header-cell> <mat-cell *matCellDef="let user ">{{user.occupation}}</mat-cell> </ng-container> <ng-container matColumnDef="action"> <mat-header-cell *matHeaderCellDef> Action </mat-header-cell> <mat-cell *matCellDef="let user"> <button mat-raised-button class="btn btn-info" (click)="userDetails(user.id)">Details</button> </mat-cell>
</ng-container> <ng-container matColumnDef="actionu"> <mat-header-cell *matHeaderCellDef> Action </mat-header-cell> <mat-cell *matCellDef="let user"> <button mat-raised-button class="btn btn-info " (click)="editUser(user.id)">Update</button> </mat-cell>
</ng-container> <ng-container matColumnDef="actiond"> <mat-header-cell *matHeaderCellDef> Action </mat-header-cell> <mat-cell *matCellDef="let user"> <button mat-raised-button class="btn btn-danger" (click)="deleteUser(user.id)">Delete</button> </mat-cell>
</ng-container> <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row> </mat-table>
<div *ngIf="isLoading" style="display: flex; justify-content: center; align-items: center; background: white;"> <h3>Loading.....</h3>
</div>
</div>
here is a link to a more readable code
dataSource is an input data array passed to a table to provide data array to a table.
<mat-table class="users-table mat-elevation-z8" [dataSource]="users" matSort>
mat-table
provides a Material Design styled data-table that can be used to display rows of data.
To display the row title we need to define
In our component.ts , create a variable in your component that contains the list of the columns you want to render.
displayedColumns = ['name', 'email', 'occupation', 'action', 'actionu', 'actiond'];
Then add mat-header-row
and mat-row
to the content of your mat-table
and provide your column list as inputs.
<mat-header-row *matHeaderRowDef="columnsToDisplay"></mat-header-row>
<mat-row *matRowDef="let myRowData; columns: columnsToDisplay"></mat-row>
To change the size of the individual columns. here is a css file for that.Add this to your style.css file. The css below reduces the size of the action buttons.
.mat-column-action {
flex: 0 0 10%;
}.mat-column-actionu {
flex: 0 0 10%;
}.mat-column-actiond {
flex: 0 0 10%;
}.mat-header-cell {
background-color:navy ;
color: white;
}h2 {
text-align: center;
}.border-class{
background-color: rgb(208, 216, 224);
}.h2-class{
font-style: italic;
font-size: 40px;
font-weight: 900;
color: navy;
}.tp-section {
display: flex;
align-content: center;
align-items: center;
height: 60px;
}.tp-margin {
margin: 0 10px;
}
update your user-list.component.ts
I have added a method to delete and router’s to navigate to add,update and details page. You need to create components for the add, update and details page as we had done above
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { User } from '../user';
import { UserService } from '../user.service';@Component({
selector: 'app-user-list',
templateUrl: './user-list.component.html',
styleUrls: ['./user-list.component.css']
})export class UserListComponent implements OnInit {
users!: User[];
id!: number;
user: User = new User();
email!: String; //search
isLoading = true;displayedColumns = ['name', 'email', 'occupation', 'action', 'actionu', 'actiond'];constructor(private userService: UserService, private router: Router,) { }ngOnInit() {
this.userService.getUsers().subscribe(data => {
console.log(data);
this.users = data;
this.isLoading = false;
})
}userDetails(id: number) {
this.router.navigate(['user', id]);
console.log(id);
}deleteUser(id: number) {
this.userService.deleteUser(id).
subscribe(data => {
console.log(data);
this.ngOnInit();
},
error => console.log(error));
}editUser(id: number) {
this.router.navigate(['update', id]);
console.log(id);
}addUser() {
this.router.navigate(['add']);
}search() {this.isLoading = true;this.users = this.users.filter(res => {
if (!this.users || !this.email) {this.userService.getUsers().subscribe(data => {this.users = data;console.log(data);})
}
else {(error: any) => console.log(error);}
return res.email.toLocaleLowerCase().match(this.email.toLocaleLowerCase());
})}}
Update the routes
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { UserListComponent } from './user-list/user-list.component';
import { UserDetailsComponent } from './user-details/user-details.component';
import { UpdateUserComponent } from './update-user/update-user.component';
import { AddUserComponent } from './add-user/add-user.component';const routes: Routes = [
{ path: '', pathMatch: 'full', redirectTo: 'users' },
{ path: 'users', component: UserListComponent },
{ path: 'user/:id', component: UserDetailsComponent },
{ path: 'update/:id', component: UpdateUserComponent },
{ path: 'add', component: AddUserComponent },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
N.B if you did not remember to edit the app.component.html.
<router-outlet></router-outlet>
Finally update the user.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';@Injectable({providedIn: 'root'})export class UserService {public baseUrl = "http://localhost:8081";constructor(private httpClient: HttpClient) {}public getUsers(): Observable<any> {
return this.httpClient.get(`${this.baseUrl}/users`);
}public getUser(id: number): Observable<any> {
return this.httpClient.get(`${this.baseUrl}/user/${id}`);
}public deleteUser(id: number): Observable<any> {
return this.httpClient.delete(`${this.baseUrl}/deleteUser/${id}`, { responseType: 'text' });
}public updateUser(id: number, value: any): Observable<any> {
return this.httpClient.put(`${this.baseUrl}/userUpdate/${id}`, value);
}public addUser(user: object): Observable<object> {
return this.httpClient.post(`${this.baseUrl}/registration`, user);
}
}
Here is a link to the complete github code.
The above code will display users list and a specific user details. Improve the UI for better appearance.
Happy coding!!!!!!!!!!!!