2

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("/");
 }

}
benfr
  • 66
  • 5
  • would it be possible to create a plunker for the application that we can test? [here's a template](https://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5?p=catalogue) – 0mpurdy Aug 02 '17 at 13:38
  • Sure! Will try to make one – benfr Aug 02 '17 at 13:44
  • I realise this is **almost certainly** not best practice but did you try pushing the state that you want to display in the url and then routing **with** `{skipLocationChange: true}` – 0mpurdy Aug 02 '17 at 13:47
  • If I understand well, you mean conditionally change `state.url` in my guards with something like `if (state.url === "/dashboard") { state.url = "/"; }` then proceed with a `this.router.navigate(['/dashboard'], { skipLocationChange: true });` ? – benfr Aug 02 '17 at 14:41
  • If it does what you want you could try it, although I don't recommend it as a **good** solution: hopefully someone else knows the correct way – 0mpurdy Aug 02 '17 at 14:44
  • Update with Plunker. Also tried your suggestion but no luck so far (not sure if I tried the correct way though !) – benfr Aug 02 '17 at 16:29

0 Answers0