在Angular中注入多个实例

时间:2018-08-13 13:57:38

标签: angular typescript dependency-injection

我试图将实例列表注入到我的Angular组件中,但是由于它不起作用并且找不到任何文档,我认为这可能是不可能的。因此,在这种情况下,我的问题是如何以一种干净的方式无需手动布线即可达到相同的效果。

例如在Spring中,我将有一些具体的动作,这些动作从抽象的Action类扩展或实现Action接口。

@Component
class MyAction1 extends Action {
   ...
}

@Component
class MyAction2 extends Action {
   ...
}

@Component
class MyConsumer {
    @Autowired
    List<Action> actions;
}

由于MyAction1MyAction2已在运行时加载,因此MyConsumer的列表将填充2个实例。不用手工就能在Angular中做到这一点吗?

编辑: 在Angular代码中,我想要的是:

export abstract class ActionBase {
...
}

@Injectable()
export class MyAction1 extends ActionBase {
...
}

@Injectable()
export class MyAction2 extends ActionBase {
...
}

@Component(...)
export class MyConsumerComponent {
    constructor(
        private availableActions: ActionBase[]
    ) { }
}

我希望MyConsumerComponent初始化后在availableActions内具有两个动作。

欢呼

3 个答案:

答案 0 :(得分:2)

  

由于MyAction1和MyAction2已在运行时加载,因此MyConsumer的列表将填充2个实例。不用手工就能在Angular中做到这一点吗?

没有,Angular中没有任何东西可以做到这一点。

Angular中的可注射物是根据需要创建的。因此,除非明确注入了提供程序,否则将不会创建该提供程序。因此,没有{em>运行时的方法MyAction2将自身添加到某个位置的数组中,因为必须先消耗掉它。例如;您可能会想将其添加到构造函数中的数组中,但是如果从未创建实例,则不会添加该实例。

始终可以选择创建自己的TypeScript装饰器,以访问全局注射器并创建自定义提供程序。我见过一些图书馆这样做,例如NGXS

我只是保持简单并手动进行。

export const PROVIDERS:Action[] = [MyAction1, MyAction2];

export const PROVIDERS_TOKEN: InjectionToken<Action[]> = new InjectionToken<Action[]>('PROVIDERS_TOKEN');

@NgModule({
     providers: [
        {provide: PROVIDERS_TOKEN: useValue: PROVIDERS}
});

然后可以通过构造函数或属性将其注入另一个组件。

@Component()
public MyComponent {
     public constructor(@Inject(PROVIDERS_TOKEN) providers: Action[]) {
     }
}

或通过媒体资源

@Component()
public MyComponent {
     @Inject(PROVIDERS_TOKEN)
     public providers: Action[];
}

答案 1 :(得分:1)

这个家伙解释了如何使用更优雅的方式多次注入同一份合约。提供程序中的属性multi令人难以置信!

https://blog.thoughtram.io/angular2/2015/11/23/multi-providers-in-angular-2.html#other-multi-providers

只需为新类OpaqueToken和您的描述更改InjectionToken

一个例子:

export const MY_TOKEN = new InjectionToken<Contract[]>('my-token');

@NgModule({
  providers: [
    { provide: MY_TOKEN, useClass: OneContract, multi: true},
    { provide: MY_TOKEN, useClass: TowContract, multi: true},
    { provide: MY_TOKEN, useClass: ThreeContract, multi: true},
  ]
})
export class MyModule { }

在您的ComponentService中:

@Injectable({ providedIn: 'root'})
export class MyService
{
  constructor(@Inject(MY_TOKEN) private readonly contracts: Contract[]) {}
}

答案 2 :(得分:0)

通过构造函数完成:

export class MyClass {
  constructor(
    private service: MyService
  ) {}
}

在构造函数参数中使用访问修饰符可创建一个实例成员,这意味着您不必像在Java中那样手动将其连接到类成员。

在Angular中,用@Injectable()装饰的类是单例,可以注入到这样的组件中。服务就是其中之一。

编辑我不认为您可以一次注入多个类,也不能检查一个类是否实现了接口(可以,但这与接口无关)。

您能做的就是使用ApplicationRef获取应用程序中当前所有组件的所有实例,检查它们是否具有所需的组件并对其进行操作。