9
votes

I am very new to angular 4 and angular material and i am still at learning phase. I am trying to create an app where user logs in and navigates to dashboard. Now i am showing a header component in dashboard and hiding it in login page. But when i refresh the browser on dashboard the header component doesnt loads. I used This Tutorial to create the PoC

Now i am not able to figure out the solution.Any help would be appreciated. Thanks in Advance...!!!

Please find my code below

app.module.ts

        import { BrowserModule } from '@angular/platform-browser';
        import { NgModule } from '@angular/core';
        import { HttpClientModule, HttpClient } from '@angular/common/http';
        import { HttpModule } from '@angular/http';
        import { RouterModule, Routes } from '@angular/router';
        import 'hammerjs';
        import { NgxPhoneSelectModule } from 'ngx-phone-select';
        import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
        import { FormsModule, ReactiveFormsModule } from '@angular/forms';
        import { MatInputModule, MatButtonModule, MatSelectModule } from '@angular/material';
        import { MatGridListModule } from '@angular/material';
        import { MatTableModule } from '@angular/material';
        import { MaterialModule } from './modules/material/material.module';


        import { AppComponent } from './app.component';
        import { CustomerComponent } from './components/customer/customer.component';
        import { LoginComponent } from './components/login/login.component';
        import { ForgetPasswordComponent } from './components/forget-password/forget-password.component';
        import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component';
        import { DashboardComponent } from './components/dashboard/dashboard.component';

        import { FleetDataService } from './services/fleet-data.service';
        import { LoaderService } from './services/loader.service';
        import { HeaderComponent } from './components/header/header.component';
        import { AuthService } from './services/auth.service';
        import { AuthGuard } from './services/auth.guard';
        const appRoutes: Routes = [
          {
            path: '',
            component: LoginComponent
          },
          {
            path: 'create-customer',
            component: CustomerComponent,
            //        canActivate: [AuthGuard] // ristrict direct access of links
          },
          {
            path: 'forget-password',
            component: ForgetPasswordComponent,
            //        canActivate: [AuthGuard] // ristrict direct access of links
          },
          {
            path: 'dashboard',
            component: DashboardComponent,
                      canActivate: [AuthGuard] // ristrict direct access of links
          },
          {
            path: '**',
            component: PageNotFoundComponent
          }
        ];

        @NgModule({
          declarations: [
            AppComponent,
            CustomerComponent,
            LoginComponent,
            ForgetPasswordComponent,
            PageNotFoundComponent,
            DashboardComponent,
            HeaderComponent
          ],
          imports: [
            BrowserModule,
            HttpClientModule,
            HttpModule,
            RouterModule.forRoot(appRoutes),
            NgxPhoneSelectModule,
            BrowserAnimationsModule,
            FormsModule,
            ReactiveFormsModule,
            MatInputModule,
            MatButtonModule,
            MatSelectModule,
            MatGridListModule,
            MatTableModule,
            MaterialModule
          ],
          providers: [FleetDataService, LoaderService, AuthService, AuthGuard],
          bootstrap: [AppComponent]
        })
        export class AppModule { }

**app.component.ts**

        import { Component } from '@angular/core';

        @Component({
          selector: 'app-root',
          templateUrl: './app.component.html',
          styleUrls: ['./app.component.scss']
        })
        export class AppComponent {
          title = 'app';
        }

app.component.html

        <div id="fullPage">
          <app-header ></app-header>
          <router-outlet></router-outlet>
        </div>
**login.component.html**

        <div class="fstBg container-fluid">
          <div class="row">
          <div class="col-md-12 logo pull-right"></div>
            <div class="col-md-4">&nbsp;</div>
            <div class="col-md-4">
              <form [formGroup]="form" (ngSubmit)="onSubmit()">
                <div class="example-container">
                  <mat-input-container>
                    <input matInput placeholder="Username" formControlName="userName" required>
                    <mat-error *ngIf="isFieldInvalid('userName')">
                      User name cannot be empty
                    </mat-error>
                  </mat-input-container>
                  <mat-input-container>
                    <input matInput type="password" placeholder="Password" formControlName="password" required>
                    <mat-icon matSuffix (click)="hide = !hide" ngClass="{{hide ? 'glyphicon glyphicon-eye-open' : 'glyphicon glyphicon-eye-close'}}"></mat-icon>
                    <mat-error *ngIf="isFieldInvalid('userName')">
                      Password cannot be empty
                    </mat-error>
                  </mat-input-container>
                  <br /><br />
                  <button type="submit" class="btn col-md-12  orange_btn" mat-raised-button>Login</button>
                  
                  <div class="bottom-div col-md-12 text-right pd0">       
                    <a id="button_right" routerLink="forget-password" class="white_text hover_link link">Forget Password</a>
                  </div>
                  <br><br>
                </div>
              </form>
              </div>
            <div class="col-md-4">&nbsp;</div>
            </div>
        </div>

login.component.ts

        import { Component, OnInit } from '@angular/core';
        import { FormGroup, FormBuilder, Validators } from '@angular/forms';
        // import { Router } from '@angular/router';
        // import { User } from '../../models/login.interface';
        import { AuthService } from '../../services/auth.service';

        @Component({
          selector: 'app-login',
          templateUrl: './login.component.html',
          styleUrls: ['./login.component.scss']
        })
        export class LoginComponent implements OnInit {
          form: FormGroup;
          private formSubmitAttempt: boolean;
          constructor(private fb: FormBuilder,
            private authService: AuthService) {}
          ngOnInit() {
            this.form = this.fb.group({     // {5}
              userName: ['', Validators.required],
              password: ['', Validators.required]
            });
          }
          isFieldInvalid(field: string) {  // {6}
            return (
              (!this.form.get(field).valid && this.form.get(field).touched) ||
              (this.form.get(field).untouched && this.formSubmitAttempt)
            );
          }
          onSubmit() {
            if (this.form.valid) {
              this.authService.login(this.form.value); // {7}
            }
            this.formSubmitAttempt = true;
          }
        }

header.component.html

        <div class="row mrg0 hidden-xs" *ngIf="isLoggedIn$ | async as isLoggedIn">
          <div class="col-md-8 col-lg-8 col-sm-8">
            <div class="logo_div">
              <div class="logo" routerLink="user-management"></div>
            </div>
          </div>
          <div class="col-md-4 col-lg-4 col-sm-4 right_panel">
            <div class="row mrg0">
              <div class="col-md-6 col-lg-8 col-sm-6 text-right pd0 user_name"><i class="material-icons gray_icon user_name">person</i> <span>Hello Admin</span></div>    
              <div class="col-md-4 col-lg-4 col-sm-4 logout link" (click)="onLogout()" *ngIf="isLoggedIn"><a><i class="material-icons gray_icon clickable" matTooltip="Logout">exit_to_app</i>&nbsp;<span>Logout</span></a></div>
            </div>
          </div>
        </div>

header.component.ts

        import { Component, OnInit } from '@angular/core';
        import { Observable } from 'rxjs/Observable';
        import { AuthService } from '../../services/auth.service';
        @Component({
          selector: 'app-header',
          templateUrl: './header.component.html',
          styleUrls: ['./header.component.scss']
        })
        export class HeaderComponent implements OnInit {
          isLoggedIn$: Observable<boolean>;
          constructor(private authService: AuthService) { }

          ngOnInit() {
            this.isLoggedIn$ = this.authService.isLoggedIn; // {2}
          }
          onLogout() {
            this.authService.logout();                      // {3}
          }

        }

dashboard.component.ts

    import { Component } from '@angular/core';

    @Component({
      selector: 'app-dashboard',
      template: '<p>Yay! You are logged in!</p>',
      styles: []
    })
    export class DashBoardComponent {}

auth.guard

        import { Injectable } from '@angular/core';
        import {
          CanActivate,
          ActivatedRouteSnapshot,
          RouterStateSnapshot,
          Router
        } from '@angular/router';
        import { AuthService } from './auth.service';
        import { Observable } from 'rxjs/Observable';
        import 'rxjs/add/operator/take';
        import 'rxjs/add/operator/map';

        @Injectable()
        export class AuthGuard implements CanActivate {
          constructor(
            private authService: AuthService,
            private router: Router
          ) {}

          canActivate(
            next: ActivatedRouteSnapshot,
            state: RouterStateSnapshot
          ): Observable<boolean> {
            return this.authService.isLoggedIn       // {1}
              .take(1)                               // {2}
              .map((isLoggedIn: boolean) => {        // {3}
                if (!isLoggedIn) {
                  this.router.navigate(['']);  // {4}
                  return false;
                }
                return true;
              });
          }
        }

auth.service

        import { Injectable } from '@angular/core';
        import { Router } from '@angular/router';
        import { BehaviorSubject } from 'rxjs/BehaviorSubject';
        import { User } from '../models/login.interface';

        @Injectable()
        export class AuthService {
          private loggedIn = new BehaviorSubject<boolean>(false); // {1}

          get isLoggedIn() {
            return this.loggedIn.asObservable(); // {2}
          }

          constructor(
            private router: Router
          ) {}

          login(user: User) {
            if (user.userName !== '' && user.password !== '' ) { // {3}
              this.loggedIn.next(true);
              this.router.navigate(['/dashboard']);
            }
          }

          logout() {                            // {4}
            this.loggedIn.next(false);
            this.router.navigate(['']);
          }
        }

login.interface.ts

       export interface User {
       userName: string;
       password: string;
      }
4
How can you even land on the dashboard after refreshing, shouldn't the guard route you to LoginComponent?AJT82
yeah as of now its routing me to login, but something that i can always change. All i will have to do is update auth.guard with "this.router.navigate(['/dashboard']);" and instead of a flag i will be checking for auth token generated from service.pranay anand
So what is the problem now? I got a bit confused about your comment, as to what you want to achieve :)AJT82
The main issue is as soon as i refresh the observable flag get reset to false and that logs me out. I am not able to find out how can i refresh teh app but not change the state of my observablepranay anand
You need to use something to persist the data on page refresh, for example localStorage or ngrx-store together with ngrx-store-localStorage.AJT82

4 Answers

30
votes

I know I'm late, but maybe, sometime, this will help somebody. I have developed this solution and it's working

In app.component.ts have something like this:

import { Component } from '@angular/core';
import { Router, NavigationStart } from '@angular/router';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  showHead: boolean = false;

  ngOnInit() {
  }

  constructor(private router: Router) {
  // on route change to '/login', set the variable showHead to false
    router.events.forEach((event) => {
      if (event instanceof NavigationStart) {
        if (event['url'] == '/login') {
          this.showHead = false;
        } else {
          // console.log("NU")
          this.showHead = true;
        }
      }
    });
  }
}

In app.component.html

<app-header *ngIf="showHead"></app-header>
<router-outlet></router-outlet>

If you don't know about NavigationStart, go console.log(event) and see more info that are pretty helpful.

3
votes

Below is the code you can use:

app.component.html

<app-header *ngIf="!isLogin"></app-header>
<router-outlet></router-outlet>

app.component.ts

  constructor (private zone: NgZone, private router: Router) {
    this.router.events.subscribe((event: any) => {
      if (event instanceof NavigationEnd) {
        if (event.url === '/login') {
          this.login= true;
        } else {
          this.login= false;
        }
      }
    });
  }
0
votes

You can create a login component without header. Another component with header and router-outlet. On logged successfully, redirect to the component with header.

0
votes

Put your header and footer inside app.componenent and then you can manage that : check here https://github.com/alaaeddinezammel/spring_boot_angular4_mysql-frontAngular