rxjs operators in angular services
Angular 6 uses rxjs 6. You can verify this by looking at package.json file in your Angular 6 project. In this topic we will discuss using rxjs 6 operators in Angular 6 services.
In the project that we have been working with so far in this topic tutorial, we need to do some ground work before we we can create an angular service.
Creating a fake online REST API
First let's create a fake online REST API. For this we are going to use JSON-Server. We discussed what REST API is and using JSON-server in Part 63 of Angular CRUD tutorial.
The following is the JSON Server Github page
https://github.com/typicode/json-server
Execute the following NPM command to install JSON server
Create db.json file in the root project folder. Copy and paste the following JSON data in the file.
Execute the following command to start the server
At this point, fire up the browser and navigate to http://localhost:3000/employees/ to see the list of all employees along with their skills. You can test this REST API using a tool like fiddler.
Creating the required interfaces to represent Employee and Skill types
Add a file in the employee folder with name ISkill.ts. Copy and paste the following code.
Add a file in the employee folder with name IEmployee.ts. Copy and paste the following code.
Creating Angular Service
Add a file in the employee folder with name employee.service.ts. Copy and paste the following code.
RxJS 5 vs 6
An Angular 6 project, by default uses RxJS version 6. RxJS 6 has some breaking changes compared to RxJS 5.5 and older versions.
The way we import some of the classes like Observable and Subject has changed in RxJS 6.
In RxJS 5, we import Observable and Subject classes as shown below.
In RxJS 6, this has changed to
Similarly, the way we import operators also changed in RxJS 6. To import catchError operator in RxJS 5, we use the following
In RxJS 6, it has changed to the following
In RxJS 6, we import all the operators from 'rxjs/operators'
Many classes like ArrayObservable, EmptyObservable, ErrorObservable etc are also removed from v6, in favour of existing or new operators that perform the same operations.
For example, in v5 to create an ErrorObservable we might use one of the following
In v6, we use throwError() function to achieve this.
How do I know, I have to use throwError() function instead of ErrorObservable class. Well, the following GitHub article contains all the differences between RxJS v5.x and v6. A quick search (CTRL + F) on the page for ErrorObservable shows, it has been removed in favour of throwError() function.
https://github.com/ReactiveX/rxjs/blob/master/docs_app/content/guide/v6/migration.md
in v6, import throwError function from rxjs. Since ErrorObservable class is replaced by throwError function, we import it the same way we import other classes like Observable and Subject from rxjs.
Implementing ListEmployeesComponent : While we are here, let's implement ListEmployeesComponent
We want this component to display all employee details as shown below.
Copy and paste the following HTML in list-employees.component.html.
Copy and paste the following code in list-employees.component.ts
Changes in app.module.ts file
To be able to use EmployeeService in ListEmployeesComponent we have to register it. Since we want EmployeeService to be available across the entire application, Let's register it in the application root module AppModule.
Import EmployeeService and include it in the providers array of @NgModule decorator of AppModule. Employee service uses angular's HttpClient service. To be able to use this we have to import HttpClientModule in the AppModule and include it in the imports array.
First let's create a fake online REST API. For this we are going to use JSON-Server. We discussed what REST API is and using JSON-server in Part 63 of Angular CRUD tutorial.
The following is the JSON Server Github page
https://github.com/typicode/json-server
Execute the following NPM command to install JSON server
npm install -g json-server
Create db.json file in the root project folder. Copy and paste the following JSON data in the file.
{
"employees": [
{
"id": 1,
"fullName": "Mark",
"contactPreference": "email",
"email": "mark@email.com",
"phone": "5641238971",
"skills": [
{
"skillName": "C#",
"experienceInYears": 1,
"proficiency": "beginner"
},
{
"skillName": "Java",
"experienceInYears": 2,
"proficiency": "intermediate"
}
]
},
{
"id": 2,
"fullName": "John",
"contactPreference": "phone",
"email": "john@email.com",
"phone": "3242138971",
"skills": [
{
"skillName": "Angular",
"experienceInYears": 2,
"proficiency": "beginner"
},
{
"skillName": "HTML",
"experienceInYears": 2,
"proficiency": "intermediate"
},
{
"skillName": "LINQ",
"experienceInYears": 3,
"proficiency": "advanced"
}
]
}
]
}
Execute the following command to start the server
json-server --watch db.json
At this point, fire up the browser and navigate to http://localhost:3000/employees/ to see the list of all employees along with their skills. You can test this REST API using a tool like fiddler.
Creating the required interfaces to represent Employee and Skill types
Add a file in the employee folder with name ISkill.ts. Copy and paste the following code.
export interface ISkill {
skillName: string;
experienceInYears: number;
proficiency: string;
}
skillName: string;
experienceInYears: number;
proficiency: string;
}
Add a file in the employee folder with name IEmployee.ts. Copy and paste the following code.
import { ISkill } from './ISkill';
export interface IEmployee {
id: number;
fullName: string;
email: string;
phone?: number;
contactPreference: string;
skills: ISkill[];
}
Creating Angular Service
Add a file in the employee folder with name employee.service.ts. Copy and paste the following code.
import { Injectable } from '@angular/core';
import { IEmployee } from './IEmployee';
import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable()
export class EmployeeService {
baseUrl = 'http://localhost:3000/employees';
constructor(private httpClient: HttpClient) {
}
getEmployees(): Observable<IEmployee[]> {
return this.httpClient.get<IEmployee[]>(this.baseUrl)
.pipe(catchError(this.handleError));
}
private handleError(errorResponse: HttpErrorResponse) {
if (errorResponse.error instanceof ErrorEvent) {
console.error('Client Side Error :', errorResponse.error.message);
} else {
console.error('Server Side Error :', errorResponse);
}
return throwError('There is a problem with the service. We are notified & working on it. Please try again later.');
}
getEmployee(id: number): Observable<IEmployee> {
return this.httpClient.get<IEmployee>(`${this.baseUrl}/${id}`)
.pipe(catchError(this.handleError));
}
addEmployee(employee: IEmployee): Observable<IEmployee> {
return this.httpClient.post<IEmployee>(this.baseUrl, employee, {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
})
.pipe(catchError(this.handleError));
}
updateEmployee(employee: IEmployee): Observable<void> {
return this.httpClient.put<void>(`${this.baseUrl}/${employee.id}`, employee, {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
})
.pipe(catchError(this.handleError));
}
deleteEmployee(id: number): Observable<void> {
return this.httpClient.delete<void>(`${this.baseUrl}/${id}`)
.pipe(catchError(this.handleError));
}
}
RxJS 5 vs 6
An Angular 6 project, by default uses RxJS version 6. RxJS 6 has some breaking changes compared to RxJS 5.5 and older versions.
The way we import some of the classes like Observable and Subject has changed in RxJS 6.
In RxJS 5, we import Observable and Subject classes as shown below.
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
In RxJS 6, this has changed to
import { Observable, Subject } from 'rxjs';
Similarly, the way we import operators also changed in RxJS 6. To import catchError operator in RxJS 5, we use the following
import { catchError } from 'rxjs/operators/catchError';
In RxJS 6, it has changed to the following
import { catchError } from 'rxjs/operators';
In RxJS 6, we import all the operators from 'rxjs/operators'
import { map, delay, catchError } from 'rxjs/operators';
Many classes like ArrayObservable, EmptyObservable, ErrorObservable etc are also removed from v6, in favour of existing or new operators that perform the same operations.
For example, in v5 to create an ErrorObservable we might use one of the following
new ErrorObservable('Your error message');
OR
ErrorObservable.create('Your error message');
OR
ErrorObservable.create('Your error message');
In v6, we use throwError() function to achieve this.
return throwError('Your error message');
How do I know, I have to use throwError() function instead of ErrorObservable class. Well, the following GitHub article contains all the differences between RxJS v5.x and v6. A quick search (CTRL + F) on the page for ErrorObservable shows, it has been removed in favour of throwError() function.
https://github.com/ReactiveX/rxjs/blob/master/docs_app/content/guide/v6/migration.md
in v6, import throwError function from rxjs. Since ErrorObservable class is replaced by throwError function, we import it the same way we import other classes like Observable and Subject from rxjs.
import { Observable, throwError } from 'rxjs';
Implementing ListEmployeesComponent : While we are here, let's implement ListEmployeesComponent
We want this component to display all employee details as shown below.
Copy and paste the following HTML in list-employees.component.html.
<div class="table-responsive">
<table class="table table-bordered" *ngIf="employees && employees.length">
<thead>
<tr class="bg-primary">
<th>Name</th>
<th>Email</th>
<th>Phone</th>
<th>Contact Preference</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let employee of employees">
<td>{{ employee.fullName }}</td>
<td>{{ employee.email }}</td>
<td>{{ employee.phone }}</td>
<td>{{ employee.contactPreference }}</td>
<td> <button class="btn btn-primary">Edit</button> </td>
</tr>
</tbody>
</table>
</div>
Copy and paste the following code in list-employees.component.ts
import { Component, OnInit } from '@angular/core';
import { EmployeeService } from './employee.service';
import { IEmployee } from './IEmployee';
@Component({
selector: 'app-list-employees',
templateUrl: './list-employees.component.html',
styleUrls: ['./list-employees.component.css']
})
export class ListEmployeesComponent implements OnInit {
employees: IEmployee[];
constructor(private _employeeService: EmployeeService) { }
ngOnInit() {
this._employeeService.getEmployees().subscribe(
(employeeList) => this.employees = employeeList,
(err) => console.log(err)
);
}
}
Changes in app.module.ts file
To be able to use EmployeeService in ListEmployeesComponent we have to register it. Since we want EmployeeService to be available across the entire application, Let's register it in the application root module AppModule.
Import EmployeeService and include it in the providers array of @NgModule decorator of AppModule. Employee service uses angular's HttpClient service. To be able to use this we have to import HttpClientModule in the AppModule and include it in the imports array.
import { EmployeeService } from './employee/employee.service';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
declarations: [
AppComponent,
CreateEmployeeComponent,
ListEmployeesComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
ReactiveFormsModule
],
providers: [EmployeeService],
bootstrap: [AppComponent]
})
export class AppModule { }
No comments:
Post a Comment