I am building an Angular 2/4 app (and Bootstrap 4 Alpha) with an AuthGuard
but also an AnonymousGuard
to prevent already loggedIn users to access certain pages (/register
/login
/forgot
) to redirect them automatically to a DashboardComponent
.
Everything works perfectly, but I am currently struggling with the displayed URL in the client browser.
At the moment, my HomeComponent
has a path of /
and my DashboardComponent
is /dashboard
.
But for a better UX perspective, what I want to achieve is to have all our users to see a main /
URL on both cases :
- Anonymous user : project.com/ =>
HomeComponent
- LoggedIn user : project.com/ =>
DashboardComponent
I know I can achieve this by simply conditionally display my <app-home>
and <app-dashboard>
elements inside my home HTML using some *ngIf="isLoggedIn"
, but I am trying to think about a more cleaner Angular/Router way to do this (if it exist ?)
I tried the { skipLocationChange: true }
approach in my Guards and routerLinks with no success (see this), because if the user is somewhere else on my website, it will somehow keep the previous URL displayed (ex: /posts/show/
) even if it goes through my Guards.
I also tried to simply hide /dashboard
by injecting Location
and use replaceState
as per this.
This last approach seems to be close to the result I am looking for, but it doesn't work anymore as soon as the user is clicking a second time on our logo navbar (routerLink="/"
), because initialization is done.
Am I missing something ? Do you guys have other ideas ? Or should I just resign and go for the simple ngIf
solution on Home ?
I would be glad to have your reflexion and best solutions on this!
Thanks
UPDATE: Plunker here
app-routing.module.ts
const appRoutes: Routes = [
{ path: '', pathMatch: 'full', component: HomeComponent, canActivate: [AnonymousGuard] },
{ path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] },
// other stuff
{ path: '**', component: PageNotFoundComponent }
];
anonymous-guard.service.ts
isLoggedIn: boolean;
constructor(
private router: Router,
private authService: AuthService
) {
this.authService.isLoggedIn().subscribe(is => {
this.isLoggedIn = is;
});
}
canActivate(route: ActivatedRouteSnapshot): boolean {
// If Anonymous, can access the page
if (!this.isLoggedIn) { return true; }
// Else force redirect to Dashboard
this.router.navigate(['/dashboard']);
return false;
}
auth-guard.service.ts
isLoggedIn: boolean;
constructor(
private router: Router,
private authService: AuthService
) {
this.authService.isLoggedIn().subscribe(is => {
this.isLoggedIn = is;
});
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
// Original URL is accessible via the 'state: RouterStateSnapshot' parameter
let url: string = state.url;
return this.checkLogin(url);
}
canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
return this.canActivate(route, state);
}
checkLogin(url: string): boolean {
if (this.isLoggedIn) { return true; }
// Store the attempted URL
this.authService.redirectUrl = url;
// Navigate to the login page
this.router.navigate(['/login']);
return false;
}
dashboard.component.ts
import { Component, OnInit } from '@angular/core';
import { Location } from '@angular/common';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss']
})
export class DashboardComponent implements OnInit {
constructor(
private readonly location: Location
) { }
ngOnInit(): void {
this.location.replaceState("/");
}
}