Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular: Displaying target URL when resolve fails

Tags:

I have a simple resolver for a route like /orders/first:

resolve(): Promise<Order> {
    return this.orderService.get()
        .then((response) => response.order)
        .catch(error => Promise.reject(error));
}

I also have an error handler that redirects to an error page:

this.router.navigate(['/error'], { skipLocationChange: true });

I want the URL to be /orders/first so if the user refresh he might be able to view the page. This also make back button return to an incorrect page (previous previous page)

The problem is that the resolver runs before route activation so the URL doesn't change.

Is there a way to do this?


EDIT: Found this workaround:

  1. Listen to router event NavigationStart and save route to a variable
  2. Set location URL before redirecting to error page: this.location.go(nextRoute.url);
  3. Redirect with skipLocationChange set to true
like image 424
Tzach Ovadia Avatar asked Feb 05 '17 18:02

Tzach Ovadia


2 Answers

I have achieved this this way:

resolve(
  route: ActivatedRouteSnapshot,
  state: RouterStateSnapshot
): Observable<any>|Promise<any>|any {
  return this.clientService.get(route.params.id)
  .catch( err => {
    const path = this.location.path();
    this.router.navigate(["/" + err.status], {  skipLocationChange: true })
    .then( () => {
      this.location.replaceState(path);
    });

    return Observable.empty();
  })
}
like image 107
Christian Benseler Avatar answered Sep 22 '22 10:09

Christian Benseler


import { Injectable } from '@angular/core';
import { Router, NavigationError, NavigationExtras } from '@angular/router';
import { Location } from '@angular/common';

@Injectable()
export class RouterService {

    private errorRoot: string;

    constructor(
        private router: Router,
        private location: Location
    ) { }

    setRouteErrorHandler(errorRoot: string = '/error'): void {
        let errorRoute = null;
        this.errorRoot = errorRoot;
        this.router.errorHandler = (error): void => {
            this.router.navigateByUrl(errorRoot, { skipLocationChange: true })
                .then(() => this.location.go(errorRoute.url));
        };

        this.router.events
            .filter(next => next instanceof NavigationError)
            .subscribe((next) => errorRoute = next);
    }
}

And call routerService.setRouteErrorHandler() from AppModule constructor or APP_INITIALIZER

like image 32
Tzach Ovadia Avatar answered Sep 23 '22 10:09

Tzach Ovadia