1
votes

I have an angular app with two components "login" and "home". I want to guard the home component until user logs in.

I have a service which has a boolean variable "isUserLoggedIn". Based on the value of this variable, I guard my component.

Network Service -

import { Injectable } from '@angular/core';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
import { Http, Response, Headers, RequestOptions } from '@angular/http';

@Injectable()
export class NetworkService {

private isUserLoggedIn = false;

constructor(private _http:Http) {

   }

getUserLoggedIn(){
     console.log("network service ... isUserLoggedIn = "+this.isUserLoggedIn);
     return this.isUserLoggedIn;
   }

setUserLoggedIn(){
    this.isUserLoggedIn = true;
     console.log("service layer : setUserLoggedIn called .... isUserLoggedIn = "+this.isUserLoggedIn);
  }
}

My auth-guard code

import { NetworkService } from './../services/network.service';
import { Router,CanActivate } from '@angular/router';
import { Injectable } from '@angular/core';

@Injectable()
export class AuthGuard implements CanActivate{
    constructor(private networkservice:NetworkService, private router:Router){

    }

    canActivate(){
        console.log("canActivate called : userLoggedIn = "+this.networkservice.getUserLoggedIn());
        if(this.networkservice.getUserLoggedIn()){
            return true;
        }
        else{
            this.router.navigate(['/login']);
            return false;
        }
    }
}

Login Component

import { Component, OnInit } from '@angular/core';
import { NetworkService } from './../services/network.service';
import { Router } from '@angular/router';


@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css'],
  providers : [NetworkService]
})
export class LoginComponent implements OnInit {

  constructor(private networkservice : NetworkService, private router: Router) { 

  }

  ngOnInit() {
  }

  onSubmit(value:any){
    console.log("user = "+value.username+" password = "+value.password);
    if(value.username == "user" && value.password == "user"){

      this.networkservice.setUserLoggedIn();
      this.router.navigate(['/home']);

    }
    else{
      alert("Username or Password did not match !!!");
    }
 }

}

Router

import { AuthGuard } from './guards/auth.guard';
import { LoginComponent } from './login/login.component';
import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AppComponent } from './app.component'; 
import { HomeComponent } from './home/home.component'; 

export const router: Routes = [
    { path: '', redirectTo: 'login', pathMatch: 'full'},
    { path: 'home', component: HomeComponent, canActivate:[AuthGuard]},
];

export const routes: ModuleWithProviders = RouterModule.forRoot(router);

Finally my app module

import { AuthGuard } from './guards/auth.guard';

.....

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    LoginComponent,
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    JsonpModule,
    DataTablesModule,
    Ng2UploaderModule,
    routes
  ],
  providers: [NetworkService,AuthGuard],
  bootstrap: [AppComponent]
})
export class AppModule { }

For now I am using hard coded text for username and password.

My problem is that even after login component sets the "isUserLoggedIn" variable of the service to "true", the auth-guard still finds it as false. And hence I cannot navigate to "Home" component.

1

1 Answers

1
votes

This is happening because you have multiple instances of the NetworkService, so each instance can have a different logged in state.

Services that are meant to be a singleton (single instance to service the whole app) should be added only in the providers array of your root AppModule.

Your problem is that you've also added the service to LoginComponent. So, just delete this line from that component:

@Component({
  providers : [NetworkService] // <-- DELETE or this will create a new instance. 
})

Once that is gone, the NetworkService that gets injected in the constructor will be the same instance as the NetworkService that the AuthGuard queries.