【问题标题】:Is it possible to instantiate a class outside angular bootstrapModule and inject instance into the application?是否可以在 angular bootstrapModule 之外实例化一个类并将实例注入应用程序?
【发布时间】:2017-12-07 16:03:27
【问题描述】:

我正在尝试在包含platformBrowserDynamic.bootstrapModule(AppModule) 的 main.ts 文件中使用服务authService

该服务处理用户身份验证和令牌更新,我们希望它在应用程序启动之前获取用户令牌。这将避免引导应用程序、重定向到身份验证网页,然后再次引导应用程序。

下面是我们如何处理 JIT 编译器的问题,它确实有效。但是,如果您想利用 AOT(我们这样做),这将不起作用。

// main.ts

... imports ...

let windw: Window = window;
let authService = windw['authService'] = windw['authService'] || new AuthService();

  authService.userLoadededEvent
    .subscribe(user => {
      if (location.pathname.match(/silentrenew/)) {
        authService.completeSilentRenew();
      } else if (user && !user.expired) {
        platformBrowserDynamic().bootstrapModule(AppModule(authService));
      } else {
        if (location.hash.match(/id_token/)) {
          authService.completeSignIn()
        } else {
          if (location.pathname.length > 1) {
            let deeplink = location.href.replace(baseHref, '');
            localStorage.setItem('deeplink', deeplink);
          }
          authService.signIn();
        }
      }
    });

// AppModule

export const AppModule = (authService: AuthService = null) => {
  @NgModule({
    declarations: [
      AppComponent
    ],
    imports: [...],
    providers: [
      {
        provide: AuthService,
        useValue: authService
      }
    ],
    bootstrap: [AppComponent]
  })
  class AppModule { };
  return AppModule;
}

如前所述,这种方法适用于 JIT 编译,但我希望应用程序进行 AOT 编译。当我使用上面的代码进行 AOT 编译时,我从 angular 得到以下错误。 Unhandled Promise rejection: No NgModule metadata found for 'AppModule'. ; Zone: <root> ; Task: Promise.then ; Value: Error: No NgModule metadata found for 'AppModule'.

有人知道我该如何解决这个问题吗? AuthService 需要是单例的,并且需要在引导的应用程序内部和外部进行访问。


我尝试过的事情。

我尝试将 AppModule 更新为不是一个函数,而只是一个类声明,其中包含一个使用窗口 obj 中的 AuthService 的提供程序。但是,角度似乎无法访问附加了 authService 的窗口 obj。这导致 AuthService 为undefined 例如

//AppModule
let windw: Window = window;

@NgModule({
    declarations: [
      AppComponent
    ],
    imports: [...],
    providers: [
      {
        provide: AuthService,
        useValue: windw['authService'] // undefined
      }
    ],
    bootstrap: [AppComponent]
  })
  class AppModule { };

我还尝试将 AuthService 传递给 bootstrapModule() 方法。这不会导致任何引导错误,但随后我收到一个未提供AuthService 的注入器错误。我承认,我不完全确定 angular 对 bootstrapModule 的 CompilerOptions 输入上的 providers 属性做了什么。 app.component.html:18 ERROR Error: StaticInjectorError[AuthService]: NullInjectorError: No provider for AuthService!

// main.ts

... imports ...

let windw: Window = window;
let authService = windw['authService'] = windw['authService'] || new AuthService();

  authService.userLoadededEvent
    .subscribe(user => {
      if (location.pathname.match(/silentrenew/)) {
        authService.completeSilentRenew();
      } else if (user && !user.expired) {
        platformBrowserDynamic().bootstrapModule(AppModule, {
         providers: [{provide: AuthService, useValue: authService}]
        });
      } else {
        if (location.hash.match(/id_token/)) {
          authService.completeSignIn()
        } else {
          if (location.pathname.length > 1) {
            let deeplink = location.href.replace(baseHref, '');
            localStorage.setItem('deeplink', deeplink);
          }
          authService.signIn();
        }
      }
    });

// AppModule

export const AppModule = (authService: AuthService = null) => {
  @NgModule({
    declarations: [
      AppComponent
    ],
    imports: [...],
    providers: [],
    bootstrap: [AppComponent]
  })
  class AppModule { };
  return AppModule;
}

再次感谢您的帮助。

【问题讨论】:

  • 也许 forwardRef 是您想要的?基本上在定义之前添加对 authService 的引用,允许您提前使用它。 angular.io/api/core/forwardRef

标签: javascript angular dependency-injection


【解决方案1】:

应该在 Angular 应用程序之外访问类实例这一事实并不意味着它应该暴露在全局范围内。 ES 模块可以自然地提供单例,因为它们被评估一次:

export class AuthService { ... }

export default new AuthService(); // default singleton

default 模块导出将是一个单例,只要非 Angular 应用程序与 Angular 应用程序一起构建。

否则window应该在工厂函数内部使用:

export function authServiceFactory() {
  return window['authService'] || (window['authService'] = new AuthService);
}
...
providers: [
  {
    provide: AuthService,
    useFactory: authServiceFactory
  }
],
...

这是 AOT 施加的限制,因为在 Node 环境中编译应用程序时,window 并不存在。

【讨论】:

  • sry,我正在度假,错过了赏金窗口@estus
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-10
  • 2022-08-17
  • 2019-09-12
  • 1970-01-01
相关资源
最近更新 更多