Angular DI 使用模型注入令牌 class

Angular DI using injection token for model class

我想在这里做点什么,但不确定是否可以完成。 我想创建一个这样的模型 class:

import { Inject } from '@angular/core';
import {
    Element,
    Image,
} from '@situlive/situ-angular-components/contentful';

export class ImageColumn {
    title: string;
    backgroundImage: Image;
    backgroundImageAlignment: string;

    constructor(
        element: Element
    ) {
        this.title = element.fields.title;
        this.backgroundImageAlignment = element.fields.backgroundImageAlignment;
    }
}

这样我就可以在组件或服务中执行 new ImageColumn(element),它会为我绑定属性。 到目前为止很简单。

现在我遇到了麻烦 :) 我需要绑定 backgroundImage,这是通过服务完成的。我将构造函数更新为:

import { Inject } from '@angular/core';
import {
    ContentfulService,
    Element,
    Image,
} from '@situlive/situ-angular-components/contentful';

export class ImageColumn {
    title: string;
    backgroundImage: Image;
    backgroundImageAlignment: string;

    constructor(
        contentfulService: ContentfulService,
        element: Element
    ) {
        this.title = element.fields.title;
        this.backgroundImageAlignment = element.fields.backgroundImageAlignment;

        this.backgroundImage = this.contentfulService.createImage(
            element.fields.backgroundImage[0]
        );
    }
}

这很好,但会导致问题,因为现在我在任何使用 ImageColumn 的地方都必须传入 contentfulService.我真的很想能够传递服务而无需在构造函数中提供它。

我之前在使用 注入令牌 的服务中做过这件事,所以我想我可以在这里做。 我创建了一个这样的注入令牌:

import { InjectionToken } from '@angular/core';

import { ContentfulService } from '@situlive/situ-angular-components/contentful';

export const CONTENTFUL_SERVICE = new InjectionToken<ContentfulService>(
  'CONTENTFUL_SERVICE'
);

我在我的模块中提供的是这样的:

@NgModule({
  imports: [
    CommonModule,
    HttpClientModule,
    RouterModule,

    AuthModule.forRoot(environment.auth0),
    ContentfulModule.forRoot(environment.contentful),
  ],
  declarations: [FooterComponent, HeaderComponent],
  exports: [FooterComponent, HeaderComponent],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: BearerInterceptor,
      multi: true,
    },
    {
      provide: CONTENTFUL_SERVICE,
      useClass: ContentfulService,
      multi: true,
    },
  ],
})
export class CoreModule {}

所以我想我可以对我的模型这样做:

import { Inject } from '@angular/core';
import {
    ContentfulService,
    Element,
    Image,
} from '@situlive/situ-angular-components/contentful';

import { CONTENTFUL_SERVICE } from '../contentful-service.token';

export class ImageColumn {
    title: string;
    backgroundImage: Image;
    backgroundImageAlignment: string;

    constructor(
        @Inject(CONTENTFUL_SERVICE) private contentfulService: ContentfulService,
        element: Element
    ) {
        this.title = element.fields.title;
        this.backgroundImageAlignment = element.fields.backgroundImageAlignment;

        this.backgroundImage = this.contentfulService.createImage(
            element.fields.backgroundImage[0]
        );
    }
}

问题是,现在当我执行 new ImageColumn(element) 时,它会抱怨我需要 2 个参数,但只得到 1 个。 有谁知道我该如何解决这个问题?

我认为这样不行,因为您没有为 ImageColumn 声明任何 提供者。声明提供者将使 注入器 知道如何在注入 ImageColumn 时获取依赖项,如下所示:

constructor (imageColumn: ImageColumn) { } 

但由于您想手动实例化它,我不确定您能否让Angular知道如何自动解析注入令牌。

我认为您可以做的是在实例化 ImageColumn 时提供 Injector

foo.component.ts

export class FooComponent {
  constructor (private injector: Injector) { }

  ngOnInit () {
    const imgColumn = new ImageColumn(element, this.injector)
  }
}

然后在您的 ImageColumn 的构造函数中,您可以注入任何已声明提供者的内容,包括该服务:

class ImageColumn {
  constructor (private element: any, private injector: Injector) {
    this.contentfulService = this.injector.get(ContentfulService);

    /* ... */

    this.backgroundImage = this.contentfulService.createImage(
      element.fields.backgroundImage[0]
    );
  }
}