如何让@Input传入模板内的组件访问宿主组件提供的服务
解决方案
核心思路是手动指定ngTemplateOutlet使用宿主组件的注入器来渲染传入的模板,Angular为ngTemplateOutlet提供了ngTemplateOutletInjector输入参数专门处理这类注入器上下文切换的场景。
步骤1:在宿主组件中注入Injector
修改HostComponent的代码,注入Angular的Injector实例:
import { Component, Input, TemplateRef, Injector } from '@angular/core'; import { MyService } from './my.service'; @Component({ selector: 'app-host', templateUrl: './host.component.html', providers: [MyService], }) export class HostComponent { @Input() template: TemplateRef<any>; constructor(public injector: Injector) {} }
步骤2:给ngTemplateOutlet指定注入器
修改HostComponent的模板,传入injector参数:
<ng-container [ngTemplateOutlet]="template" [ngTemplateOutletInjector]="injector" ></ng-container>
修改完成后,<app-item-element>在渲染时就会使用HostComponent的注入器解析依赖,成功拿到MyService的实例。
提示:
ngTemplateOutletInjector为Angular 14及以上版本提供的API,如果使用低于14的版本,可以通过ViewContainerRef.createEmbeddedView(templateRef, context, injector)手动渲染模板,传入宿主的injector即可实现相同效果。
可选替代方案(适配特殊场景)
如果不方便修改宿主组件的注入逻辑,也可以通过模板上下文传递服务实例,侵入性稍高,需要修改两处代码:
- 宿主组件传递服务实例到模板上下文:
<ng-container [ngTemplateOutlet]="template" [ngTemplateOutletContext]="{myService: myService}" ></ng-container>
需要先在宿主组件构造函数中注入MyService实例,存为公共属性。
- 使用模板时显式接收并传递服务:
<ng-template #item let-service="myService"> <app-item-element [myService]="service"></app-item-element> </ng-template>
同时需要修改ItemElementComponent添加对应输入属性接收服务实例。
内容的提问来源于stack exchange,提问作者Don Tomato
相关产品推荐
相关产品推荐

