angularlocal-storageangular-local-storage

I'm getting local storage error in Angular


i write an angular app and i getting a error:

"ERROR ReferenceError: localStorage is not defined"

I am just use in local-storage-service:

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

@Injectable({
  providedIn: 'root',
})
export class LocalStorageService {
  constructor() {}
  setItem(key: string, value: string) {
    localStorage.setItem(key, value);
  }

  getItem(key: string) {
    return localStorage.getItem(key);
  }
}

I wrote an interceptor:

import {
  HttpEvent,
  HttpHandler,
  HttpInterceptor,
  HttpRequest,
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { LocalStorageService } from '../services/local-storage-service.service';
import { Injectable } from '@angular/core';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

  constructor(private localStorageService: LocalStorageService) {}

  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {

    let token = this.localStorageService.getItem('token');
    let newRequest: HttpRequest<any>;
    newRequest = req.clone({
      headers: req.headers.set('Authorization', 'Bearer ' + token),
    });
    return next.handle(newRequest);

  }
}

And i add this line in app.module:

providers: [{provide:HTTP_INTERCEPTORS,useClass:AuthInterceptor,multi:true},provideClientHydration()],

How can I solve this problem?

I installed this npm package: localstorage-polyfill and add this 2 line

import 'localstorage-polyfill'
global['localStorage'] = localStorage;

so my server.ts like this :

import { APP_BASE_HREF } from '@angular/common';
import { CommonEngine } from '@angular/ssr';
import express from 'express';
import { fileURLToPath } from 'node:url';
import { dirname, join, resolve } from 'node:path';
import AppServerModule from './src/main.server';
import 'localstorage-polyfill'
global['localStorage'] = localStorage;

// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
  const server = express();
  const serverDistFolder = dirname(fileURLToPath(import.meta.url));
  const browserDistFolder = resolve(serverDistFolder, '../browser');
  const indexHtml = join(serverDistFolder, 'index.server.html');

  const commonEngine = new CommonEngine();

  server.set('view engine', 'html');
  server.set('views', browserDistFolder);

  // Example Express Rest API endpoints
  // server.get('/api/**', (req, res) => { });
  // Serve static files from /browser
  server.get('*.*', express.static(browserDistFolder, {
    maxAge: '1y'
  }));

  // All regular routes use the Angular engine
  server.get('*', (req, res, next) => {
    const { protocol, originalUrl, baseUrl, headers } = req;

    commonEngine
      .render({
        bootstrap: AppServerModule,
        documentFilePath: indexHtml,
        url: `${protocol}://${headers.host}${originalUrl}`,
        publicPath: browserDistFolder,
        providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
      })
      .then((html) => res.send(html))
      .catch((err) => next(err));
  });

  return server;
}

function run(): void {
  const port = process.env['PORT'] || 4000;

  // Start up the Node server
  const server = app();
  server.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`);
  });
}

run();

but problem is still same.


Solution

  • Try this:

     //LocalStorageService
     constructor(@Inject(PLATFORM_ID) platformId: object) {}
    
     setItem(key: string, value: string) {
       if (isPlatformBrowser(platformId)) {
        localStorage.setItem(key, value);
      }
     }
    
      getItem(key: string) {
       if (isPlatformBrowser(platformId)) {
        return localStorage.getItem(key);
       }
       return null;
      }
    

    The thing is that when you use SSR you must validate if its a browser to use window related objects, there are many ways to do this (check for example using domino), the example im giving you is a very simple one, but it could work.

    Another way is to provide the localStorage with a factory, and validate if isPlatformBrowser, if not you could return a mocked localStorage.