Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set URL to the cancelled path when redirecting to the 404 page from a resolver

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)

like image 697
Hristo Avatar asked Jan 18 '17 17:01

Hristo


1 Answers

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.

like image 85
Víťa Plšek - angular.cz Avatar answered Oct 13 '22 00:10

Víťa Plšek - angular.cz