Let's say we have the following route configuration:
[{
path: "people",
children: [
{
path: ":id",
component: PersonProfileComponent,
resolve: { person: PersonResolver },
children: [
{ path: "", component: PersonOverviewComponent },
{ path: "photos", component: PersonPhotoListComponent }
]
}
]
},
{ path: "404", component: PageNotFoundComponent },
{ path: "**", component: PageNotFoundComponent }]
I want to redirect to the 404 page when user try to navigate to any of these:
/people/{non-existing-id}
/people/{non-existing-id}/photos
/people/{existing-id}/{non-existing-subpage}
The third case is handled by the ** route since it's not matched by any of the previous routes. So the PersonResolver
has to handle the first two cases.
export class PersonResolver implements Resolve<Person> {
constructor(private peopleService: PeopleService, private router: Router) { }
resolve(route: ActivatedRouteSnapshot): Observable<Person> {
return this.peopleService.find(id).catch(error => {
if (error instanceof Response) {
if (error.status === 404) {
this.router.navigate(["/404"]);
}
else {
//todo
}
}
else {
//todo
}
return Observable.of(null);
});
}
}
Everything works but the problem is that when the 404 page is shown the browser URL is updated to <hostname>/404
(as expected). My question is how to set the URL to the path we've just cancelled (eg. <hostname>/people/fake-id/photos
) as this is how 404 is handled all over the web. (I also tried passing {skipLocationChange: true}
to router.navigate()
but this keeps the location before that we are trying to navigate to)
Its possible to change url without navigating using Location
- docs
You can react on error with subscribing to Router.events - NavigationError
and then show 404 with skipLocationChange
and then change location with location.go
You have to change url after navigation to 404 is complete.
constructor(router: Router, location: Location) {
router.events
.filter(event => event instanceof NavigationError)
.subscribe((event: NavigationError) => {
router.navigate(["/404"], {skipLocationChange: true})
.then(() => location.go(event.url));
})
}
I would prefer doing this in my routing module, but it could be done also in resolver.
Router.events
are not very well documented yet, you can check at least list of them here and do some logging.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With