In my resolve guard I am getting an Http Observable to return the JSON of a user from a particular id
.
I want to catch an error and reroute to the users overview if the id
does not exist. I have seen code that solves that with a Promise, but not with an Observable. I would like to see a solution with an Observable!
Currently I get an "EXCEPTION: Uncaught (in promise): Response with status: 404 Not Found for URL: http://127.0.0.1:3000/users/191"
since user 191 does not exsist.
Here is my code:
Resolve:
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, ActivatedRoute } from '@angular/router';
import { UsersService } from '../shared/services/users.service';
import { User } from '../shared/models/user';
@Injectable()
export class UserResolveService implements Resolve<User> {
user: User;
constructor(private service: UsersService) {}
resolve(route: ActivatedRouteSnapshot) {
let id = route.params['id'];
// getUser returns an Http Observable
return this.service.getUser(id);
// ERROR HANDLING IF id DOES NOT EXIST
// REROUTE TO USER OVERVIEW
// A TUTORIAL WITH PROMISE USES FOLLOWING CODE
// .then(user => {
// if (user) {
// return user;
// } else {
// // navigate the user back to the users page
// this.router.navigate(['/users']);
// return false;
// }
// });
}
}
UsersService getUser(id):
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { environment } from "../../../environments/environment";
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
@Injectable()
export class UsersService {
private _url = environment.RAILS_API_BASE_URL+"/users";
constructor(private http :Http) { }
...
getUser(userId){
return this.http.get(this.getUserUrl(userId))
.map(res => res.json())
}
...
private getUserUrl(userId){
return this._url + "/" + userId;
}
}
user.routing.ts:
import { Routes, RouterModule } from '@angular/router';
import { ModuleWithProviders } from '@angular/core';
import { UsersResolveService } from './users-resolve.service';
import { UserResolveService } from './user-resolve.service';
import { UsersComponent } from './users.component';
import { UserDetailComponent } from './user-detail.component';
import { UserSectionComponent } from './user-section.component';
const userRoutes: Routes = [
{
path: '',
component: UserSectionComponent,
children: [
{
path: ':id',
component: UserDetailComponent,
resolve: {
user: UserResolveService
}
}
]
}
]
export const UsersRouting: ModuleWithProviders = RouterModule.forChild(userRoutes)
UserDetailComponent:
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router'
import { UsersService } from '../shared/services/users.service';
import { User } from '../shared/models/user';
@Component({
templateUrl: './user-detail.component.html',
styleUrls: ['./user-detail.component.scss']
})
export class UserDetailComponent implements OnInit {
user: User;
constructor(private route: ActivatedRoute) { }
ngOnInit() {
// OLD CALL without resolve
// let id = this.route.snapshot.params['id'];
// this.user = this.usersService.getUser(id)
// .subscribe((res) => {this.user = res;}, error => {console.log(error)});
// NEW CALL WITH RESOLVE
this.route.data.forEach((data: { user: User }) => this.user = data.user );
}
}
You can use the
catch
operator to be able to handle an error without subscribing yourself: