0

I am programming a Single Page Application using Angular/Typescript. The application starts with an Login Page. When the user is authenticated a new page is loaded using this line of code:

this.router.navigate(['/productionFiles']);

And that works fine! Also two of the router paths are decorated with canactivate [ AuthGuard ]

This canactivate works well when the applications routes the user to the productionfiles page. But a refresh on the same page gives following error:

Exception: Call to Node module failed with error: Error: Uncaught (in promise): Error: No provider for AuthGuard!

Also when i enter manually the URL same error raises?

I know this error has many more questions here. But this is little different i think. So it al seems to be working oke, except if there is a browser refresh, or a manually entered URL.

In the authentication service a localstorage('currentuser') is being set:

localStorage.setItem('currentUser', JSON.stringify(user));

Since i use the SPA template for visual studio, there are 3 app.module files:

App.Module.Shared.Ts:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { RouterModule, Routes  } from '@angular/router';

import { AppComponent } from './components/app/app.component';
import { HomeComponent } from './components/home/home.component';
import { HeaderComponent } from './components/Header/header.component';
import { ProductionfileComponent } from     './components/ProductionFile/productionfile.component';
import { ProductionFileSummary } from './components/ProductionFile/productionfilesummary.component';
import { ProductionFileDetailComponent } from './components/ProductionFile/productionfiledetail.component';
import { LoginComponent } from './components/Login/login.component';
import { AuthGuard } from './components/Login/auth.guard';

export const sharedConfig: NgModule = {

declarations: [
        AppComponent,
        HomeComponent,
        HeaderComponent,
        ProductionfileComponent,
        ProductionFileSummary,
        ProductionFileDetailComponent,
        LoginComponent
    ],
    imports: [
        RouterModule.forRoot([
            { path: '', redirectTo: 'login', pathMatch: 'full' },
            { path: 'login', component: LoginComponent },
            { path: 'productionFiles', component: ProductionfileComponent,     canActivate: [ AuthGuard ] },
            { path: 'productionfiledetail/:prodHeaderOrdNr', component:     ProductionFileDetailComponent, canActivate:  [ AuthGuard ] },
            { path: '**', redirectTo: 'login' }
        ]),
        BrowserModule,
        FormsModule
    ],
    providers: [AuthGuard],
    bootstrap: [AppComponent]
};

App.Module.Client.ts:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { sharedConfig } from './app.module.shared';

@NgModule({    
    declarations: sharedConfig.declarations,
    imports: [
        BrowserModule,
        FormsModule,
        HttpModule,
        ...sharedConfig.imports
    ],
    providers: [ sharedConfig.providers,
        { provide: 'ORIGIN_URL', useValue: location.origin }
    ],
    bootstrap: [sharedConfig.bootstrap]
})
export class AppModule {
}

App.Module.Server.ts:

import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { sharedConfig } from './app.module.shared';

@NgModule({

    declarations: sharedConfig.declarations,
    imports: [
        ServerModule,
        ...sharedConfig.imports
    ],
    providers: sharedConfig.providers,
    bootstrap: sharedConfig.bootstrap
})
export class AppModule {
}

Can someone please put me on the right track??

rollstuhlfahrer
  • 3,988
  • 9
  • 25
  • 38
Nulajo
  • 31
  • 3
  • localStorage is not available when using server side rendering – David Mar 01 '18 at 08:35
  • I just find out. I changed the Auth.Guard Code, don't know if it's correct. But it's working know, the way i except it: – Nulajo Mar 01 '18 at 08:52

2 Answers2

0

I found out, that localstorage is not available/defined after browser refresh. So I changed the Auth.Guard.Ts code. Don't if it's correct, but it's working know the way i expect it.

import { Injectable } from '@angular/core';
import { Router, ActivatedRoute, CanActivate } from '@angular/router';

@Injectable()
export class AuthGuard implements CanActivate {

    constructor(private router: Router,
                private actvRoute: ActivatedRoute) { }

    canActivate() {
        console.log('AuthGuard.CanActivate')
        //return true;

        try {
            if (localStorage.getItem('currentUser')) {
                // logged in so return true
                return true;
            }

            // not logged in so redirect to login page
            this.router.navigate(['/login']);
            return false;

        } catch (e) {

        }
    }
}
Nulajo
  • 31
  • 3
0

I think the proper way is to use isPlatformBrowser to identify whether you are executing the code client side or server side

import { isPlatformBrowser } from '@angular/common';
import { PLATFORM_ID } from '@angular/core';

constructor(private router: Router,
            private actvRoute: ActivatedRoute, @Inject(PLATFORM_ID) platformId: Object) { }

canActivate() {
    console.log('AuthGuard.CanActivate')
    //return true;

    if(isPlatformBrowser(this.platformId))//<== means you are client side
    {
        if (localStorage.getItem('currentUser')) {
            // logged in so return true
            return true;
        }

        // not logged in so redirect to login page
        this.router.navigate(['/login']);
        return false;
    }
    else
    {
       //server side
    }

}
David
  • 33,444
  • 11
  • 80
  • 118