首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >未定义localStorage (角通用)

未定义localStorage (角通用)
EN

Stack Overflow用户
提问于 2016-08-22 17:43:08
回答 13查看 55.8K关注 0票数 38

我正在使用万能起动器作为骨干。

当我的客户端启动时,它从localStorage读取一个关于用户信息的令牌。

代码语言:javascript
复制
@Injectable()
export class UserService {
  foo() {}

  bar() {}

  loadCurrentUser() {
    const token = localStorage.getItem('token');

    // do other things
  };
}

所有操作都很好,但是我在服务器端(终端)中得到了这一点,因为服务器呈现:

例外: ReferenceError: localStorage未定义

我从ng-conf-2016-通用-模式那里得到了这样的想法:使用依赖注入来解决这个问题。但是那个演示真的很古老。

假设我现在有这两份文件:

main.broswer.ts

代码语言:javascript
复制
export function ngApp() {
  return bootstrap(App, [
    // ...

    UserService
  ]);
}

main.node.ts

代码语言:javascript
复制
export function ngApp(req, res) {
  const config: ExpressEngineConfig = {
    // ...
    providers: [
      // ...
      UserService
    ]
  };

  res.render('index', config);
}

现在,它们使用的UserService都是相同的。有人能给出一些代码来解释如何使用不同的依赖注入来解决这个问题吗?

如果有另一种更好的方法,而不是依赖注入,那也会很酷。

更新1我使用的是角2 RC4,我尝试了@Martin的方式。但是,即使我导入了它,它仍然会在下面的终端中出错:

终端(npm启动)

/my-project/node_modules/@angular/core/src/di/reflective_provider.js:240抛出新的reflective_exceptions_1.NoAnnotationError(typeOrFunc,参数);^reflective_exceptions_1.NoAnnotationError(typeOrFunc,:无法解析“UserService”的所有参数(Http,?)。确保所有参数都使用Inject修饰,或者具有有效的类型注释,并且“UserService”使用可注入的修饰。

终端(npm运行表)

错误TS2304:找不到名称“LocalStorage”。

我想它在某种程度上复制了angular2-universal中的angular2-universal(虽然我没有使用import { LocalStorage } from 'angular2-universal';),但是即使我试图将自己的import { LocalStorage } from 'angular2-universal';转换成LocalStorage2,仍然不起作用。

同时,我的IDE WebStorm也显示为红色:

顺便说一下,我找到了一个import { LocalStorage } from 'angular2-universal';,但不知道如何使用它。

更新2,我更改为(不确定是否有更好的方法):

代码语言:javascript
复制
import { Injectable, Inject } from '@angular/core';
import { Http } from '@angular/http';
import { LocalStorage } from '../../local-storage';

@Injectable()
export class UserService {
  constructor (
    private _http: Http,
    @Inject(LocalStorage) private localStorage) {}  // <- this line is new

  loadCurrentUser() {
    const token = this.localStorage.getItem('token'); // here I change from `localStorage` to `this.localStorage`

    // …
  };
}

这解决了UPADAT 1中的问题,但现在在终端中出现了错误:

例外: TypeError: this.localStorage.getItem不是一个函数

EN

回答 13

Stack Overflow用户

回答已采纳

发布于 2016-08-23 10:32:25

更新角形的更新版本

OpaqueTokenInjectionToken所取代,它的工作方式与InjectionToken大同小异--只不过它有一个通用接口InjectionToken<T>,可以更好地进行类型检查和推断。

原语答案

有两件事:

  1. 您没有注入任何包含localStorage对象的对象,而是试图作为全局对象直接访问它。任何全球访问都应该是发现某些问题的第一条线索。
  2. nodejs中没有window.localStorage。

您需要做的是为localStorage注入一个适配器,该适配器将同时适用于浏览器和NodeJS。这也会给您提供可测试的代码。

在本地储藏室:

代码语言:javascript
复制
import { OpaqueToken } from '@angular/core';

export const LocalStorage = new OpaqueToken('localStorage');

在您的main.browser.ts中,我们将从浏览器中注入实际的localStorage对象:

代码语言:javascript
复制
import {LocalStorage} from './local-storage.ts';

export function ngApp() {
  return bootstrap(App, [
    // ...

    UserService,
    { provide: LocalStorage, useValue: window.localStorage}
  ]);

然后在main.node.ts中,我们将使用一个空对象:

代码语言:javascript
复制
... 
providers: [
    // ...
    UserService,
    {provide: LocalStorage, useValue: {getItem() {} }}
]
...

然后,您的服务注入了以下内容:

代码语言:javascript
复制
import { LocalStorage } from '../local-storage';

export class UserService {

    constructor(@Inject(LocalStorage) private localStorage: LocalStorage) {}

    loadCurrentUser() {

        const token = this.localStorage.getItem('token');
        ...
    };
}
票数 32
EN

Stack Overflow用户

发布于 2019-09-04 05:15:58

这些步骤解决了我的问题:

步骤1:运行以下命令:

代码语言:javascript
复制
npm i localstorage-polyfill --save

步骤2:server.ts文件中添加这两行:

代码语言:javascript
复制
import 'localstorage-polyfill'

global['localStorage'] = localStorage;

完成后,运行build命令(例如:npm run build:serverless)

都准备好了。再次启动服务器,您可以看到问题已经解决。

注:使用localStorage而不是window.localStorage,例如:localStorage.setItem(keyname, value)

票数 41
EN

Stack Overflow用户

发布于 2017-11-20 00:12:55

在角4(和5)中,您可以通过以下简单的函数轻松地处理此类问题:

app.module.ts

代码语言:javascript
复制
@NgModule({
    providers: [
        { provide: 'LOCALSTORAGE', useFactory: getLocalStorage }
    ]
})
export class AppModule {
}

export function getLocalStorage() {
    return (typeof window !== "undefined") ? window.localStorage : null;
}

如果您有一个服务器/客户端拆分文件AppModule,那么将它放在app.module.shared.ts文件中--该函数不会破坏您的代码--除非您需要对服务器和客户端构建强制执行完全不同的行为;如果是这样的话,那么更明智的做法是实现一个自定义类工厂,就像在其他答案中显示的那样。

无论如何,一旦您完成了提供程序实现,就可以在任何角组件中注入LOCALSTORAGE泛型,并在使用它之前使用角本机isPlatformBrowser函数检查平台类型:

代码语言:javascript
复制
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.
        }
    }
}

值得注意的是,由于如果窗口对象不可用,getLocalStorage()函数将返回null,因此只需检查this.localStorage可空性,并完全跳过平台类型检查。但是,我强烈建议采用上述方法,因为函数实现(和返回值)将来可能会发生更改;相反,isPlatformBrowser / isPlatformServer返回值是可以由设计信任的。

要获得更多信息,请查看我所写的关于这个主题的这篇博客文章

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39085632

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档