1

I have an app, with 3 links: Home (/), Sign in (/user/sign-in) and User Detail (/user).

When user click Home, my app will be show content public

When user click User Detail, my app will be show popup sign in, if user cancel sign in popup, my app will be keep current location, not change to /user.

But i don't know detect route change start event and cancel this. Please help me. Thanks.

Nho Huynh
  • 674
  • 6
  • 13

3 Answers3

2

I think you could extend router outlet to implement such processing. Something like this:

@Directive({
  selector: 'auth-outlet'
})
export class AuthOutlet extends RouterOutlet {
  publicRoutes: any;
  private parentRouter: Router;
  private authService: AuthService;
  constructor(_elementRef: ElementRef, 
            _loader: DynamicComponentLoader, 
           _parentRouter: Router,
           @Attribute('name') nameAttr: string, 
           _authService: AuthService) {
    (...)
  }

  activate(oldInstruction: ComponentInstruction) {
    var url = this.parentRouter.lastNavigationAttempt;
    console.log('attemping to nav');
    if (!this.publicRoutes[url] && !this.authService.loggedIn){
      var newInstruction = new ComponentInstruction('Login', [], new RouteData(), Login, false, 1);
      return super.activate(newInstruction);
    } else {
      return super.activate(oldInstruction);
    }
  }
}

The activate method is called when a route will be displayed. You can add at this level your processing.

You use this directive this way un your template:

@Component({
  (...)
  template: '<auth-outlet></auth-outlet>',
  directives: [ AuthOutlet ]
})
(...)

See these links for more details:

Another option is to use the CanActivate decorator but it's per component and can't be applies globally.

Community
  • 1
  • 1
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • please check my comment in your given link. I wonder if it ever returns url from `var url = this.parentRouter.lastNavigationAttempt;` – micronyks Mar 13 '16 at 10:14
  • @ThierryTemplier What would this look like now for the latest router? `ComponentInstruction` does not exist anymore and `lastNavigationAttempt` is not a exposed property on router. In fact, router is null inside `activate()`. – lbrahim Aug 30 '16 at 12:39
1

For this I'll implement authService concept and before accessing any protected route, I'll check whether user is authenticated or not.If user is not authenticated I'll redirect him to login page.There if you want cancel button too, the you can put cancel button in LOGIN Component and when you press it you can redirect user back to previous component by using CanActive hook in Login Component). Just try to learn this and if you want any further help i'm here.

auth.ts

import {Observable} from 'rxjs/Observable';

export class Auth {
  constructor() {
    this.loggedIn = false;
  }

  login() {
    this.loggedIn = true;
  }

  logout() {
    this.loggedIn = false;
  }

  check() {
    return Observable.of(this.loggedIn);
  }
}

For further code check out,

  • this plunker which is nicely written for protected routes
  • This implementation will surely help you for your use-case.

    micronyks
    • 54,797
    • 15
    • 112
    • 146
    1

    An unofficial solution that I found to this is to throw a NavigationCancelingError through an observable or a promise. Angular's router will catch this error type, cancel the navigation, and reset the current route. For example, this can be done in a resolve like so:

    import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router';
    import { NavigationCancelingError } from '@angular/router/src/shared';
    import { Observable } from 'rxjs';
    
    export class CancelingResolve implements Resolve<any> {
        constructor(private router: Router) {}
    
        resolve(route: ActivatedRouteSnapshot): Observable<any> {
            this.router.navigate(['new-route']); // Router will navigate here after canceling the activated route.
            return Observable.throw(new NavigationCancelingError());
        }
    }
    

    Note: Works under Angular 2.3.1

    Matt Strom
    • 595
    • 8
    • 13
    • Where do you inject this class ? – Piou Jun 21 '17 at 14:05
    • `NavigationCancelingError` does not need to be injected. `CancelingResolve` should be specified in the `resolve` property of a route configuration. See https://angular.io/guide/router#resolve-pre-fetching-component-data. – Matt Strom Jun 25 '17 at 21:38
    • I can't have it called. I added created a topmost empty route with all my routes as children and the property `resolve: myResolver` and the resolve function is never called. – Piou Jun 29 '17 at 13:48