localStorage is not defined (Angular Universal)

后端 未结 13 2281
情书的邮戳
情书的邮戳 2020-11-29 01:26

I am using universal-starter as backbone.

When my client starts, it read a token about user info from localStorage.

@Injectable()
export class UserSe         


        
相关标签:
13条回答
  • 2020-11-29 02:01

    You can use PLATFORM_ID token to check whether the current platform is browser or server.

    import { Component, OnInit, Inject, PLATFORM_ID } from '@angular/core';
    import { isPlatformBrowser } from '@angular/common';
    
    @Component({
      selector: "app-root",
      templateUrl: "./app.component.html"
    })
    export class AppComponent implements OnInit {
    
       constructor(@Inject(PLATFORM_ID) private platformId: Object) {  }
    
       ngOnInit() {
    
         // Client only code.
         if (isPlatformBrowser(this.platformId)) {
            let item = {key1: 'value1', key2: 'valu2' };
            localStorage.setItem( itemIndex, JSON.stringify(item) );
         }
    
       }
     }
    
    0 讨论(0)
  • 2020-11-29 02:03

    Solved "getItem undefined" issue by below lines :

    if(window.localStorage){
          return window.localStorage.getItem('user');
    }
    
    0 讨论(0)
  • 2020-11-29 02:06

    These steps resolved my issue:

    Step 1: Run this command:

    npm i localstorage-polyfill --save
    

    Step 2: Add these two lines in server.ts file:

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

    Once you are done, run build command (eg: npm run build:serverless)

    All set now. Start the server again and you can see the issue is resolved.

    Note: Use localStorage not window.localStorage, eg: localStorage.setItem(keyname, value)

    0 讨论(0)
  • 2020-11-29 02:06

    LocalStorage not implemented by the server side. We need to choose to write depend on platform code or use a cookie for save and read data. ngx-cookie is best solution(that i know) for work with cookie on server and browser. You can write extend Storage class with cookie work: universal.storage.ts

    import { Injectable } from '@angular/core';
    import { CookieService } from 'ngx-cookie';
    
    @Injectable()
    export class UniversalStorage implements Storage {
      [index: number]: string;
      [key: string]: any;
      length: number;
      cookies: any;
    
      constructor(private cookieService: CookieService) {}
    
      public clear(): void {
        this.cookieService.removeAll();
      }
    
      public getItem(key: string): string {
        return this.cookieService.get(key);
      }
    
      public key(index: number): string {
        return this.cookieService.getAll().propertyIsEnumerable[index];
      }
    
      public removeItem(key: string): void {
        this.cookieService.remove(key);
      }
    
      public setItem(key: string, data: string): void {
        this.cookieService.put(key, data);
      }
    }
    
    0 讨论(0)
  • 2020-11-29 02:07

    In Angular 4 (and 5) you can easily deal with such issue with a simple function in the following way:

    app.module.ts

    @NgModule({
        providers: [
            { provide: 'LOCALSTORAGE', useFactory: getLocalStorage }
        ]
    })
    export class AppModule {
    }
    
    export function getLocalStorage() {
        return (typeof window !== "undefined") ? window.localStorage : null;
    }
    

    If you have a server/client split file AppModule, place it in the app.module.shared.ts file - the function won't break your code - unless you need to enforce completely different behaviours for the server and client builds; if that’s the case, it could be wiser to implement a custom class factory instead, just like it has been shown in other answers.

    Anyway, once you're done with the provider implementation, you can inject the LOCALSTORAGE generic in any Angular component and check for the platform type with the Angular-native isPlatformBrowser function before using it:

    import { PLATFORM_ID } from '@angular/core';
    import { isPlatformBrowser, isPlatformServer } from '@angular/common';
    
    @Injectable()
    export class SomeComponent {
        constructor(
            @Inject(PLATFORM_ID) private platformId: any,
            @Inject('LOCALSTORAGE') private localStorage: any) {
    
            // do something
    
        }
    
        NgOnInit() {
            if (isPlatformBrowser(this.platformId)) {
                // localStorage will be available: we can use it.
            }
            if (isPlatformServer(this.platformId)) {
                // localStorage will be null.
            }
        }
    }
    

    It’s worth noting that, since the getLocalStorage() function will return null if the window object isn’t available, you could just check for this.localStorage nullability and entirely skip the platform type check. However, I strongly recommend the above approach as that function implementation (and return value) might be subject to change in the future; conversely, the isPlatformBrowser / isPlatformServer return values are something that can be trusted by design.

    For more info, check out this blog post that I wrote on the topic.

    0 讨论(0)
  • 2020-11-29 02:15

    I have no sufficient knowledge of preparing angular apps to run serverside. But in the similar scenario for react & nodejs, what needs to be done is to let server know what localStorage is. For example:

    //Stub for localStorage
    (global as any).localStorage = {
      getItem: function (key) {
        return this[key];
      },
      setItem: function (key, value) {
        this[key] = value;
      }
    };
    

    Hope this can be of any help to you.

    0 讨论(0)
提交回复
热议问题