angular 2 show/hide router-outlet and redirect to html page

12,781

In Angular 2 Routes you have 'CanActivate' and 'CanActivateChild' property. This can be used for authorization before rendering the component.

You can find the usage here: https://angular.io/docs/ts/latest/guide/router.html#!#can-activate-guard

In your case, you do not have to remove the router-outlet.

Instead:

  1. Add only <router-outlet></router-outlet> in your app.component.html.
  2. Provide 2 routes

    1. Default route for your main component which requires authorization.
    2. A separate route(/contact) for your contact component which is linked with the contact.html.

      Import RouterModule in app module to add routes.
      example:

      RouterModule.forRoot([
      {
          path: '',
          canActivate: [AuthGuard] //provide the Injectable class here to authenticate.
          component: MainComponent
      },
      {
          path: 'contact',
          component: ContentComponent
      }
      ])
  3. Create an @Injectable class as a guard to authenticate the user. This will call the app service to authenticate the user and redirect to contact component if unauthorized. You can use this.router.navigate(['contact']); import Router from "@angular/router"

  4. Add this new @Injectable class as the CanActivate property for your default route.
Share:
12,781
Kamran Pervaiz
Author by

Kamran Pervaiz

Updated on June 05, 2022

Comments

  • Kamran Pervaiz
    Kamran Pervaiz almost 2 years

    I have created a simple application. I have AD windows authentication web api which is on different domain so I have enabled cors. I have created a spike of api and returning 401 when not authorized.

    app.service.ts

    authenticateUser(): Observable<any> {
            return this.http.get("http://localhost:36655/", { withCredentials: true })
                .map(this.extractData)
                .catch(this.handleError);
        }
    

    app.component.ts

    @Component({
        moduleId: module.id,
        selector: 'app-root',
        templateUrl: 'app.component.html',
        styleUrls: ['app.component.css']
    })
    export class AppComponent {
    
        constructor(appService: AppService) {
            appService.authenticateUser()
                .subscribe(response => {
    
                    //do something here because its not 401
                },
                error => {
                    if (error.indexOf("401") >= 0)
                        console.log("Redirect to contact page")
                    else {
    
                    }
                });
        }
    }
    

    There are 2 things I am struggling with

    1. how do I hide Router-Outlet (reason is I don't want to show my main page/links)
    2. I can hide it using [hidden] on the main div but then how do I redirect? because <router-outlet></router-outlet> will be invisible

    app.component.html

    <div>
        <nav class="navbar navbar-default">
            <div class="container-fluid">
                <a class="navbar-brand" [routerLink]="['']">Home</a>
                <ul class="nav navbar-nav">
                    <li><a [routerLink]="['/factory']" id="factory" name="factory">Factory</a></li>
                    <li><a [routerLink]="['/supplier']" id="supplier" name="supplier">Supplier</a></li>
                    <li><a [routerLink]="['/businessarea']" id="businessArea" name="businessArea">Business Area</a></li>
                </ul>
            </div>
        </nav>
        <router-outlet></router-outlet>
    </div>
    

    I have access all or no-access authentication that's why I dont want to show anything. Is there something like

    router.navigate('../shared/contact.html')?

    Edit 1:

    app.component.ts

    @Component({
        moduleId: module.id,
        selector: 'app-root',
        templateUrl: 'app.component.html',
        styleUrls: ['app.component.css']
    })
    export class AppComponent {
        private isAuthenticated: boolean = false;
    
        constructor(private authService: AuthService) {
            this.authService.authenticateUser()
                .subscribe(response => {
                    if (response.status == 200)
                        this.isAuthenticated = true;
                },
                error => {
                    if (error.indexOf("401") >= 0)
                        this.isAuthenticated = false;
                });
        }
    }
    

    authguard.ts

    @Injectable()
    export class AuthGuard implements CanActivate {
    
        private isActive: boolean = true;
        constructor(private authService: AuthService, private router: Router) {
        }
    
        canActivate(): boolean {
            this.authService.authenticateUser()
                .subscribe(() => {},
                error => {
                    if (error.indexOf("401") >= 0) {
                        let link = ['contactus'];
                        this.router.navigate(link);
                        this.isActive = false;
                    }
                });
            return this.isActive;
        }
    }
    

    auth.service.ts

    @Injectable()
    export class AuthService {  
        constructor(private http: Http) {
    
        }
    
        authenticateUser(): Observable<any> {
            return this.http.get("http://localhost:5002/api/v1/authenticate", { withCredentials: true })
                .map(this.extractData)
                .catch(this.handleError);
        }
    
        private extractData(response: Response) {
            let body = response;
            return body || {};
        }
    
        private handleError(error: Response) {
            let errMsg: string;
            if (error instanceof Response) {
                errMsg = `${error.status} - ${error.statusText || ''}`;
            } else {
                errMsg = error.toString();
            }
            return Observable.throw(errMsg);
        }
    }
    

    app.component.html

    <div>
        <nav class="navbar navbar-default">
            <div class="container-fluid">
                <a class="navbar-brand" [routerLink]="['']">Ethos</a>
                <ul class="nav navbar-nav" *ngIf="isAuthenticated">
                    <li><a [routerLink]="['/factory']" id="factory" name="factory">Factory</a></li>
                    <li><a [routerLink]="['/supplier']" id="supplier" name="supplier">Supplier</a></li>
                    <li><a [routerLink]="['/businessarea']" id="businessArea" name="businessArea">Business Area</a></li>
                </ul>
            </div>
        </nav>
        <div>
            <router-outlet></router-outlet>
        </div>
    </div>
    

    app.routes.ts

    const routes: Routes = [
        {
            path: '', component: HomeComponent, pathMatch: 'full', canActivate: [AuthGuard]
        },
        { path: 'factory', component: FactoryFormComponent, canActivate: [AuthGuard]},
        //...some other
        { path: 'contactus', component: ContactUsComponent }
    ];
    

    AuthenticateController.cs

    public HttpResponseMessage Get()
            {
                return User.Identity.IsAuthenticated ? new HttpResponseMessage(HttpStatusCode.OK) : new HttpResponseMessage(HttpStatusCode.Unauthorized);
            }
    

    I can hide the menu fine but homeComponent which is search textbox renders before authentication, I want to hide everything and just want to show Logo. this search for factory textbox should not be displayed and there is data like gridview at the bottom which i am not showing in this picture.

    enter image description here

    It does not redirect until Cancel is clicked...another solution is just like I hid the menu I do it on homeComponent but there are many authService calls going around which is not elegant i guess