Praveen Rana
Praveen Rana

Reputation: 440

How to use localStorage in angular universal?

I am using @angular v4.0.3 and webpack 2.2.0.

It was working fine using Auler post but as I included localStorage it stopped working. Is there any way to make it work or any module for localStorage in angular universal

Upvotes: 5

Views: 5360

Answers (3)

Surya R Praveen
Surya R Praveen

Reputation: 3745

Angular Universal Set Localstorage using simple Platform Browser or Platform Server Here is the component file

components.ts

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

@Component({
  selector: 'app-navigation',
  templateUrl: './navigation.component.html',
  styleUrls: ['./navigation.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NavigationComponent implements OnInit {
  locale_Menu: any = [];
  defaultURL: any;
  defaultURLpath: any;
  private isBrowser: boolean = false;

  constructor(
    @Inject(DOCUMENT) private dom: Document,
    private router: Router,
    @Inject(PLATFORM_ID) private platformId: Object
  ) {
    this.isBrowser = isPlatformBrowser(platformId);
  }

  ngOnInit(): void {
    this.generalAppSettings.subscribe((location: any) => {
      this.locale_Menu = location.localeMenu.continents;
    });
    this.defaultURL = new URL(this.dom.URL);
    this.defaultURLpath = this.defaultURL?.pathname.split('/');
    if (this.defaultURLpath.length == 2) {
      if (this.isBrowser) {
        var retrievedLocale = localStorage?.getItem('preferredLocale');

        if (retrievedLocale) {
          const navigateURL = this.defaultURL?.pathname.replace(
            this.defaultURLpath[1],
            retrievedLocale
          );
          this.router.navigate([navigateURL]);
        } else {
          this.router.navigate([this.defaultURL]);
        }
      }
    }
  }

  changeLocale(category: any): void {
    const locale = this.coreService.locales.find((l) => l.code === category);
    if (locale) {
      let _URL = this.defaultURL.pathname.replace(
        this.defaultURL.pathname.split('/')[1],
        locale.code
      );
      if (this.defaultURLpath.length == 2) {
        window.localStorage.setItem('preferredLocale', locale.code);
      }

      this.router.navigate([_URL]).then(() => {
        window.location.reload();
      });
    }
  }
}

Upvotes: 0

Santi Barbat
Santi Barbat

Reputation: 2315

This happens because using Angular Universal for Server Side Rendering, the Angular app runs in both the Nodejs server and the client browser. At this point, the server app does not have a reference to the localStorage object, because it is only available on the client-side.

There's an article I wrote about this with the solution implemented: How to use localStorage on Angular 9 Universal (SSR)

Upvotes: 2

Estus Flask
Estus Flask

Reputation: 222498

A good way is to make localStorage an injectable and provide different implementations for it.

An abstract class that reflects Storage API can be used as a token:

export abstract class LocalStorage {
    readonly length: number;
    abstract clear(): void;
    abstract getItem(key: string): string | null;
    abstract key(index: number): string | null;
    abstract removeItem(key: string): void;
    abstract setItem(key: string, data: string): void;
    [key: string]: any;
    [index: number]: string;
}

Then for browser app module it is

export function localStorageFactory() {
  return localStorage;
}
...
{ provide: LocalStorage, useFactory: localStorageFactory }

And for server app module localStorage can be replaced with some implementation, like node-storage-shim for in-memory storage:

{ provide: LocalStorage, useClass: StorageShim }

Using DI instead of global persistent storage also makes testing easier.

Upvotes: 7

Related Questions