Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Angular2, how to redirect to previous url before login redirect

Using Angular2 to create a single page app, I'm intercepting unauthenticated user access to non-public routes in a custom RouterOutlet and redirecting them to a login view. After a successful login, I want to redirect the user to their originally requested view, rather than the default view.

I've noticed that Router has a renavigate() function that navigates to the last successful route BUT the last successful route was /auth/login and not the originally requested url.

Basically : How can I access, or determine the previously requested url?

I don't really want to resort to passing query string parameters around, unless I really have to. Ideally it would be nice to have access to history collection as part of the Router component, similar to backbone.history!

like image 655
Jon Miles Avatar asked Dec 31 '15 12:12

Jon Miles


3 Answers

  1. Use Auth Guards (implements CanActivate) to prevent unauthenticated users. See official documentation with examples and this blog.
  2. Use RouterStateSnapshot in the auth guard to capture the requested URL.

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) 
    {
        // keep the attempted URL for redirecting
        this._loginService.redirectUrl = state.url;
    }
    
  3. Redirect to that URL on successful authentication with using Router (e.g. in the login.component.ts). E.g. this._router.navigateByUrl(redirectUrl);

P.S. Suggestions of @MichaelOryl and @Vitali would work, but my way is more aligned with Angular2 final release.

like image 120
Alex Klaus Avatar answered Oct 11 '22 16:10

Alex Klaus


You might find what you need in the docs for the Location class. The back() function could possibly do it for you.

Another approach would be to subscribe to the popstate events in Location, instead. MDN has docs talking about the values you could expect to receive.

class MyCLass {
  constructor(private location: Location) {
    location.subscribe((val) => {
        // do something with the state that's passed in
    })
  }
}

Otherwise you might want a service that tracks the changes in the Router so that you can access them.

class MyTrackingService {
  constructor(private router: Router) {
    router.subscribe((val) => {
        // store the routes here so that you can peel them off as needed?
    })
  }
}

In this case I'm accessing the Router object and subscribing to any changes so that I could track them.

like image 8
Michael Oryl Avatar answered Oct 11 '22 17:10

Michael Oryl


This worked for me. Inject it into your main App component's constructor having registered it in the bootstrap method. The first val on page load should be the original URL. I am unsubscribing right after to be efficient since I don't (perhaps, yet) want to listen to subsequent router events in this service. Inject the service into other places where originalUrl is needed.

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';

@Injectable()
export class UrlTrackingService {

  public originalUrl: string;

  constructor(
    private router: Router
  ) {
    let subscription: Subscription = this.router.events.subscribe((val) => {
      this.originalUrl = val.url;
      subscription.unsubscribe();
    });
  }

}
like image 6
Vitali Kniazeu Avatar answered Oct 11 '22 16:10

Vitali Kniazeu