An error message of the angular server-side rendering application – localstorage is not defined

Time:2022-5-24

In angular application development, we call localstorage in typescript code

It retrieves data from local storage through key. However, on the server, this code crashes with an error message:
ReferenceError: localStorage is undefined

When running the angular application on the server, the standard browser API is missing from the global space

For example, in server-side rendering mode, developers cannot directly access global document objects as in client-side rendering environment. To obtain a reference to a document, you must use the document token and the angular dependency injection mechanism di

Do not use browser APIs through global space, but replace or disable browser implementations through Di so that they can be used safely on the server

Refer to the following code:

import {Component, Inject, NgModule} from '@angular/core';
import {LOCAL_STORAGE} from '@ng-web-apis/common';

@Component({...})
export class SomeComponent {
  constructor(@Inject(LOCAL_STORAGE) localStorage: Storage) {
    localStorage.getItem('key');
  }
}

The above example uses local from the @ ng web APIs / common package_ Storage token. But when we run this code on the server, we get an error. Just add universal from the @ ng web APIs / universal package from the providers of appservermodule_ LOCAL_ Store and pass the token local_ Storage, so you can get the localstorage implementation of the server.

import { NgModule } from '@angular/core';
import {
    ServerModule,
} from '@angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
import { UNIVERSAL_LOCAL_STORAGE } from '@ng-web-apis/universal';

@NgModule({
  imports: [
    AppModule,
    ServerModule,
  ],
  providers: [UNIVERSAL_LOCAL_STORAGE],
  bootstrap: [AppComponent],
})
export class AppServerModule {}

Look at the following conditional rendering code:

<>
@Component({
  selector: 'ram-root',
  template: '<some-сomp *ngIf="isServer"></some-сomp>',
  styleUrls: ['./app.component.less'],
})
export class AppComponent {
  isServer = isPlatformServer(this.platformId);
    
  constructor(@Inject(PLATFORM_ID) private platformId: Object){}
}

This angular component needs to obtain platform_ ID, target platform, and understand the public properties of the class. This attribute will be used with the ngif directive in the template.

We have a more elegant implementation:

First create an injection token:

<>
export const IS_SERVER_PLATFORM = new InjectionToken<boolean>('Is server?', {
  factory() {
    return isPlatformServer(inject(PLATFORM_ID));
  },
});

Then create a custom Directive:

@Directive({
  selector: '[ifIsServer]',
})
export class IfIsServerDirective {
  constructor(
    @Inject(IS_SERVER_PLATFORM) isServer: boolean,
    templateRef: TemplateRef<any>,
    viewContainer: ViewContainerRef
  ) {
    if (isServer) {
      viewContainer.createEmbeddedView(templateRef);
    }
  }
}

Then directly use the structure directive on the component:

<>
@Component({
  selector: 'ram-root',
  template: '<some-сomp *ifIsServer"></some-сomp>',
  styleUrls: ['./app.component.less'],
})
export class AppComponent {}

Additional properties have been removed from the component. The component template is now simpler, focusing only on the business logic it wants to implement.

Recommended Today

Agent ARP of HCNP Routing & Switching

Previously, we learned about the topics related to port isolation. For review, please refer tohttps://www.cnblogs.com/qiuhom-1874/p/16186451.html; Today, let’s talk about ARP agent related topics; The solution of port isolation As we can see from the packet capture above, when the ports under the same VLAN are isolated by two-way ports or one-way ports, the corresponding ports […]