Angular如何向指定子组件传递服务作为依赖注入值
动态向子组件树注入指定服务实例的实现方案
该需求可以完全实现,核心思路是通过自定义指令构造专属注入器,不需要修改深层组件的注入逻辑,就能让array-item下所有后代组件通过@Inject(FormService)拿到绑定的对应实例,和@Component({providers: []})的作用域效果完全一致。
具体实现步骤
- 第一步:编写自定义注入指令,接收外部传入的服务实例,替换当前节点的注入器
import { Directive, Input, ViewContainerRef, Injector, TemplateRef, EmbeddedViewRef, OnChanges } from '@angular/core'; // 公开API兼容版指令,无版本兼容风险 @Directive({ selector: '[provideInstance]' }) export class ProvideInstanceDirective implements OnChanges { @Input('provideInstance') instance: any; @Input() provideToken: any; @Input() template!: TemplateRef<any>; constructor( private viewContainerRef: ViewContainerRef, private parentInjector: Injector ) {} ngOnChanges(): void { // 清空之前的视图 this.viewContainerRef.clear(); // 基于父注入器创建自定义注入器,绑定传入的实例到对应token const customInjector = Injector.create({ providers: [{ provide: this.provideToken || this.instance.constructor, useValue: this.instance }], parent: this.parentInjector }); // 用自定义注入器创建嵌入视图,视图内所有组件都从该注入器取服务 this.viewContainerRef.createEmbeddedView( this.template, {}, { injector: customInjector } ); } }
- 第二步:在父组件模板中使用该指令,绑定动态创建的FormService实例即可,用法和预期基本一致:
<ng-container *ngFor="let s of formServices"> <ng-template [provideInstance]="s" [provideToken]="FormService"> <array-item></array-item> </ng-template> </ng-container>
效果说明
- 不需要给
array-item加@Input传值,也不需要修改array-item本身的providers配置 array-item组件本身,以及它内部所有深层后代组件(比如TextInputComponent),只要在构造函数写constructor(private formService: FormService),拿到的就是当前循环绑定的独立FormService实例- 父组件中创建的FormService实例完全可控,支持动态增减、替换实例,父子组件访问到的是同一个实例
注意:如果FormService是
@Injectable装饰的类,不传provideToken时指令会默认用实例的构造类作为注入token,和直接写providers: [FormService]的匹配规则一致,多数场景可以省略[provideToken]配置。如果想要更简洁的写法、不介意使用Angular内部稳定属性,也可以直接操作视图容器的_hostLView替换注入器,不需要套ng-template,写法和你预期的[inject/providers]="s"几乎一致。
内容的提问来源于stack exchange,提问作者DaveLV2
相关产品推荐
相关产品推荐

