Andrei Dobrin
Andrei Dobrin

Reputation: 1185

ReferenceError: localStorage is not defined

I am trying to make User Authentication with Angular and ASP.NET Core.

I am following the tutorial found here:

https://fullstackmark.com/post/10/user-authentication-with-angular-and-asp-net-core

I followed all the steps with no errors.

The app runs, but when I go to "/register" or "/login" routes, I get

NodeInvocationException: Uncaught (in promise): ReferenceError: localStorage is not defined
ReferenceError: localStorage is not defined

the service that uses it is:

import { Injectable, Inject } from '@angular/core';
import { Http, Response, Headers, RequestOptions } from '@angular/http';

import { UserRegistration } from '../shared/models/user.registration.interface';
import { ConfigService } from '../shared/utils/config.service';

import { BaseService } from "./base.service";

import { Observable } from 'rxjs/Rx';
import { BehaviorSubject } from 'rxjs/Rx';

//import * as _ from 'lodash';

// Add the RxJS Observable operators we need in this app.
import '../rxjs-operators';

@Injectable()
export class UserService extends BaseService {

  baseUrl: string = '';

  // Observable navItem source
  private _authNavStatusSource = new BehaviorSubject<boolean>(false);
  // Observable navItem stream
  authNavStatus$ = this._authNavStatusSource.asObservable();

  private loggedIn = false;

  constructor(private http: Http, private configService: ConfigService) {
    super();
    this.loggedIn = !!localStorage.getItem('auth_token');
    // ?? not sure if this the best way to broadcast the status but seems to resolve issue on page refresh where auth status is lost in
    // header component resulting in authed user nav links disappearing despite the fact user is still logged in
    this._authNavStatusSource.next(this.loggedIn);
    this.baseUrl = configService.getApiURI();
  }

    register(email: string, password: string, firstName: string, lastName: string,location: string): Observable<UserRegistration> {
    let body = JSON.stringify({ email, password, firstName, lastName,location });
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });

    return this.http.post(this.baseUrl + "/accounts", body, options)
      .map(res => true)
      .catch(this.handleError);
  }  

   login(userName: any, password: any) {
    let headers = new Headers();
    headers.append('Content-Type', 'application/json');

    return this.http
      .post(
      this.baseUrl + '/login',
      JSON.stringify({ userName, password }),{ headers }
      )
      .map(res => res.json())
      .map(res => {
        localStorage.setItem('auth_token', res.auth_token);
        this.loggedIn = true;
        this._authNavStatusSource.next(true);
        return true;
      })
      .catch(this.handleError);
  }

  logout() {
    localStorage.removeItem('auth_token');
    this.loggedIn = false;
    this._authNavStatusSource.next(false);
  }

  isLoggedIn() {
    return this.loggedIn;
  }  
}

the register ts is:

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

import { UserRegistration } from '../../shared/models/user.registration.interface';
import { UserService } from "../../services/user.service";

declare var localStorage: any;

@Component({
  selector: 'app-registration-form',
  templateUrl: './registration-form.component.html'
})
export class RegistrationFormComponent implements OnInit {

 errors: string;  
 isRequesting: boolean;
 submitted: boolean = false;

 constructor(private userService: UserService, private router: Router) { 

 }

  ngOnInit() {

  }

  registerUser({ value, valid }: { value: UserRegistration, valid: boolean }) {
     this.submitted = true;
     this.isRequesting = true;
     this.errors='';
     if(valid)
     {
         this.userService.register(value.email,value.password,value.firstName,value.lastName,value.location)
                   .finally(() => this.isRequesting = false)
                   .subscribe(
                     result  => {if(result){
                         this.router.navigate(['/login'],{queryParams: {brandNew: true,email:value.email}});                         
                     }},
                     errors =>  this.errors = errors);
     }      
  }  
}

the login is:

import { Subscription } from 'rxjs';
import { Component, OnInit,OnDestroy } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';

import { Credentials } from '../../shared/models/credentials.interface';
import { UserService } from '../../services/user.service';

@Component({
  selector: 'app-login-form',
  templateUrl: './login-form.component.html'
})
export class LoginFormComponent implements OnInit, OnDestroy {

  private subscription: Subscription;

  brandNew: boolean;
  errors: string;
  isRequesting: boolean;
  submitted: boolean = false;
  credentials: Credentials = { email: '', password: '' };

  constructor(private userService: UserService, private router: Router,private activatedRoute: ActivatedRoute) { }

    ngOnInit() {

    // subscribe to router event
    this.subscription = this.activatedRoute.queryParams.subscribe(
      (param: any) => {
         this.brandNew = param['brandNew'];   
         this.credentials.email = param['email'];         
      });      
  }

   ngOnDestroy() {
    // prevent memory leak by unsubscribing
    this.subscription.unsubscribe();
  }

  login({ value, valid }: { value: Credentials, valid: boolean }) {
    this.submitted = true;
    this.isRequesting = true;
    this.errors='';
    if (valid) {
      this.userService.login(value.email, value.password)
        .finally(() => this.isRequesting = false)
        .subscribe(
        result => {         
          if (result) {
             this.router.navigate(['/home']);             
          }
        },
        error => this.errors = error);
    }
  }
}

I tried the solution from:

localStorage is not defined (Angular Universal)

but it does not work...

What am I missing

Upvotes: 13

Views: 54821

Answers (5)

MB_18
MB_18

Reputation: 2251

Before getting data from localStorage, you should check if the local storage is undefined by adding the following condition:

if (typeof localStorage !== 'undefined') {
  const data = localStorage.getItem(key)
  // rest of the code ...
}

Upvotes: 0

Nicola Gaioni
Nicola Gaioni

Reputation: 178

You are probably getting this error because the component is looking for localStorage when rendering server side, which is why it cannot be found and you are getting this error message.

I had a similar problem in React and solved it by simply importing the component dynamically, disabling SSR. Even just disabling SSR should be fine, you can choose whether to do this on import or export.

Hope this solves your problem

Upvotes: 2

Rakesh Chand
Rakesh Chand

Reputation: 3113

You can use standard API for localstorage, like

localStorage.setItem(key, val)

and

localStorage.getItem(key)

but If you want a angular solution for this and find a good library for localstorage, one I'm using is this

https://github.com/marcj/angular2-localstorage

also

https://www.npmjs.com/package/angular2-cool-storage

is cool to use.

Upvotes: 5

D.Quang
D.Quang

Reputation: 11

Put localStorage.getItem(...) on `ComponentDidMount()``

Upvotes: 0

k11k2
k11k2

Reputation: 2044

The standard localStorage API should be available.

No need to declare it.

to set localStorage.setItem('name', 'storingSomething');

to get localStorage.getItem('name');

Upvotes: 3

Related Questions