In this video we will discuss error handling in Angular.
When using http, to call a web service, errors may occur. When they do occur we want to handle these errors.
1. We use the catch operator to catch any exceptions that occur.
2. Before we use the catch operator we have to import it, just like how we imported map operator.
import 'rxjs/add/operator/catch';
3. The catch operator can then be chained to the map operator.
return this._http.get('http://localhost:24535/api/employeess')
.map((response: Response) => <IEmployee[]>response.json())
.catch(this.handleError);
4. To the catch operator we are passing another method (handleError). This handleError() method is called when there is an exception.
handleError(error: Response) {
console.error(error);
return Observable.throw(error);
}
5. In a real world application we may pass the error to a logging service to log the error to a file or a database table, so the developers can see these errors and fix them if required.
6. In our case, to keep things simple we are logging to the browser console.
7. Since we want the error message color to be red so it stands out, we are using console.error() method instead of console.log() method to log the error to the browser console.
8. After we log the error, we are throwing the error back, so the components that use this service are notified about the error condition, so they can display a meaningful error message to the user.
9. To use throw, we will have to import it from rxjs
import 'rxjs/add/Observable/throw';
Here is the complete code in employee.service.ts
We are calling this service from EmployeeListComponent. So we need to handle the error we have thrown from the service and display a meaningful message to the user. We are subscribing to the service, in ngOnInit() life cycle hook of EmployeeListComponent.
Notice there are 2 parameters to the subscribe() function. Both these parameters are arrow functions. The first arrow function is called when the Observable successfully emits an item. The second arrow function is called, when there is an error.
ngOnInit() {
this._employeeService.getEmployees()
.subscribe(
employeesData => this.employees = employeesData,
error => {
console.error(error);
this.statusMessage = 'Problem with the service. Please try again after sometime';
});
}
Here is the complete code in employeeList.component.ts : Notice the code that is relevant to exception handling is commented and self-explanatory
At this point run the application, and notice since we do not have any errors, that data is loaded as expected. Now let's introduce an error. In employee.component.ts file
Change the url from
http://localhost:24535/api/employees
To (Notice the extra "s" at the end)
http://localhost:24535/api/employeess
At this point when you reload the page in the browser, you will see the message "Loading data. Please wait...", but the data never loads.
Now launch browser developer tools and you will see the error message logged to the console by the service.
This message - "Loading data. Please wait..." is misleading in this case. Instead we should be displaying a meaningful message like - "Problem with the service. Please try again after sometime".
To do this in the view template of EmployeeListComponent (employeeList.component.html) bind to statusMessage property of the EmployeeListComponent class as shown below.
With the above change, while the service is busy retrieving data, we see the message "Loading data. Please wait..." and if there is an error we see the message "Problem with the service. Please try again after sometime"
If you comment the following import statement in employee.service.ts, the exception handling still works as expected.
import 'rxjs/add/Observable/throw';
However, without the above import statement in employee.service.ts file, if you try to log the error object to the console in ngOnInit() method of EmployeeListComponent as shown below, the logging does not work as expected.
With the above change notice the second error message logged to the console. You will see a message stating - observable_1.observable.throw is not a function, which is not the error message we expected. Angular is complaining that it cannot find throw.
If you uncomment the import statement in employee.service.ts file, then we see the error message we expect.
1. We use the catch operator to catch any exceptions that occur.
2. Before we use the catch operator we have to import it, just like how we imported map operator.
import 'rxjs/add/operator/catch';
3. The catch operator can then be chained to the map operator.
return this._http.get('http://localhost:24535/api/employeess')
.map((response: Response) => <IEmployee[]>response.json())
.catch(this.handleError);
4. To the catch operator we are passing another method (handleError). This handleError() method is called when there is an exception.
handleError(error: Response) {
console.error(error);
return Observable.throw(error);
}
5. In a real world application we may pass the error to a logging service to log the error to a file or a database table, so the developers can see these errors and fix them if required.
6. In our case, to keep things simple we are logging to the browser console.
7. Since we want the error message color to be red so it stands out, we are using console.error() method instead of console.log() method to log the error to the browser console.
8. After we log the error, we are throwing the error back, so the components that use this service are notified about the error condition, so they can display a meaningful error message to the user.
9. To use throw, we will have to import it from rxjs
import 'rxjs/add/Observable/throw';
Here is the complete code in employee.service.ts
import { Injectable } from '@angular/core';
import { IEmployee } from './employee';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/Observable/throw';
@Injectable()
export class EmployeeService {
constructor(private _http: Http) { }
getEmployees(): Observable<IEmployee[]> {
return this._http.get('http://localhost:24535/api/employees')
.map((response: Response) => <IEmployee[]>response.json())
.catch(this.handleError);
}
handleError(error: Response) {
console.error(error);
return Observable.throw(error);
}
}
We are calling this service from EmployeeListComponent. So we need to handle the error we have thrown from the service and display a meaningful message to the user. We are subscribing to the service, in ngOnInit() life cycle hook of EmployeeListComponent.
Notice there are 2 parameters to the subscribe() function. Both these parameters are arrow functions. The first arrow function is called when the Observable successfully emits an item. The second arrow function is called, when there is an error.
ngOnInit() {
this._employeeService.getEmployees()
.subscribe(
employeesData => this.employees = employeesData,
error => {
console.error(error);
this.statusMessage = 'Problem with the service. Please try again after sometime';
});
}
Here is the complete code in employeeList.component.ts : Notice the code that is relevant to exception handling is commented and self-explanatory
import { Component, OnInit } from '@angular/core';
import { IEmployee } from './employee';
import { EmployeeService } from './employee.service';
@Component({
selector: 'list-employee',
templateUrl: 'app/employee/employeeList.component.html',
styleUrls: ['app/employee/employeeList.component.css'],
providers: [EmployeeService]
})
export class EmployeeListComponent implements OnInit {
employees: IEmployee[];
// The view template will bind to this property to display
// "Loading data. Please wait..." message when the data is
// being loaded. If there is an error the second arrow
// function in the subscribe method sets this property to
// "Problem with the service. Please try again after sometime"
statusMessage: string = 'Loading data. Please wait...';
selectedEmployeeCountRadioButton: string = 'All';
constructor(private _employeeService: EmployeeService) {
}
ngOnInit() {
// The second arrow function sets the statusMessage property
// to a meaningful message that can be displayed to the user
this._employeeService.getEmployees()
.subscribe(
employeesData => this.employees = employeesData,
error => {
this.statusMessage =
'Problem with the service. Please try again after sometime';
});
}
getTotalEmployeesCount(): number {
return this.employees.length;
}
getTotalMaleEmployeesCount(): number {
return this.employees
.filter(e => e.gender === 'Male').length;
}
getTotalFemaleEmployeesCount(): number {
return this.employees.filter(e => e.gender === 'Female').length;
}
onEmployeeCountRadioButtonChange(selectedRadioButtonValue: string): void {
this.selectedEmployeeCountRadioButton = selectedRadioButtonValue;
}
}
At this point run the application, and notice since we do not have any errors, that data is loaded as expected. Now let's introduce an error. In employee.component.ts file
Change the url from
http://localhost:24535/api/employees
To (Notice the extra "s" at the end)
http://localhost:24535/api/employeess
At this point when you reload the page in the browser, you will see the message "Loading data. Please wait...", but the data never loads.
Now launch browser developer tools and you will see the error message logged to the console by the service.
This message - "Loading data. Please wait..." is misleading in this case. Instead we should be displaying a meaningful message like - "Problem with the service. Please try again after sometime".
To do this in the view template of EmployeeListComponent (employeeList.component.html) bind to statusMessage property of the EmployeeListComponent class as shown below.
<tr *ngIf="!employees">
<td colspan="5">
{{statusMessage}}
</td>
</tr>
With the above change, while the service is busy retrieving data, we see the message "Loading data. Please wait..." and if there is an error we see the message "Problem with the service. Please try again after sometime"
If you comment the following import statement in employee.service.ts, the exception handling still works as expected.
import 'rxjs/add/Observable/throw';
However, without the above import statement in employee.service.ts file, if you try to log the error object to the console in ngOnInit() method of EmployeeListComponent as shown below, the logging does not work as expected.
ngOnInit() {
this._employeeService.getEmployees()
.subscribe(
employeesData => this.employees = employeesData,
error => {
this.statusMessage =
'Problem with the service. Please try again after sometime';
// Notice here we are logging the error to the browser console
console.error(error);
});
}
With the above change notice the second error message logged to the console. You will see a message stating - observable_1.observable.throw is not a function, which is not the error message we expected. Angular is complaining that it cannot find throw.
If you uncomment the import statement in employee.service.ts file, then we see the error message we expect.
0 comments:
Post a Comment
Note: only a member of this blog may post a comment.