从指令访问外部组件实例
Posted
技术标签:
【中文标题】从指令访问外部组件实例【英文标题】:Access outer component instance from directive 【发布时间】:2020-05-29 02:57:42 【问题描述】:我有一个带有单个输入 [id] 的简单组件,以及一个使用“my-directive”的模板。
<div>
<div my-directive>
hello world
</div>
</div>
simple-component 将在模板中多次使用:
<simple-component [id]="1"></simple-component>
<simple-component [id]="2"></simple-component>
我是否可以从每个 my-directive 实例中访问 simple-component 的实例?
目标是每个 my-directive 实例都知道它们的简单组件“主机/外部”实例, 例如,访问他们的 'id' 属性。
【问题讨论】:
在这里查看我的示例:***.com/questions/53057340/… 【参考方案1】:是的,有一种方法可以使用@Host()
分辨率修饰符访问父组件(有关official documentation 的更多信息)。基本思想是通过使用依赖注入来导航组件树,以便从子元素中找到对父元素的引用。有几个很好的例子here。
默认情况下,Angular 会向上搜索提供的实例直到 NullInjector
(层次结构中的最高层)。如果它没有找到实例,它就会抛出异常,除非我们使用@Optional
,在这种情况下它会返回null
。
在您的具体示例中,我们使用 Host()
告诉 Angular 停止搜索,将此组件作为搜索时的最后一站。我们不必使用它,即使我们省略了Host()
,它仍然可以工作。
在my-directive.directive.ts
文件中:
constructor(@Host() private parent: SimpleComponent)
// here we have an instance of SimpleComponent and we can access its properties except for the Input properties, those are still not set in constructor
我创建了一个简单的 stackblitz 示例来演示这一点。
编辑:这是example,我们在其中找到AppComponent
的实例,它是指令 中SimpleComponent
的父级。这里我们不能使用Host()
,因为搜索会以指令作为最后一站停止(并且AppComponent
在链中更高)。所以我们只是不添加任何东西,我们得到了正确的参考。
希望这会有所帮助。
【讨论】:
【参考方案2】:您可以使用服务来实现:
@Injectable()
export class IdsTrackerService
private ids$$: BehaviorSubject< [key: string]: true > = new BehaviorSubject(
);
public ids$: Observable<string[]> = this.ids$$
.asObservable()
.pipe(map(ids => Object.keys(ids)));
public addId(id: string): void
if (!this.ids$$.value[id])
this.ids$$.next(
...this.ids$$.value,
[id]: true
);
然后在您的指令中,您只需在创建指令时注册一个 ID,并在销毁时取消注册:
@Directive(
selector: "[appTrackId]"
)
export class TrackIdDirective implements OnInit, OnDestroy
@Input() appTrackId: string | undefined;
constructor(private idsTrackerService: IdsTrackerService)
public ngOnInit(): void
if (!this.appTrackId)
throw new Error(`When using "appTrackId" please pass the ID as argument`);
this.idsTrackerService.addId(this.appTrackId);
// you now also have access to
// this.idsTrackerService.ids$ :) !
public ngOnDestroy(): void
this.idsTrackerService.removeId(this.appTrackId);
不要忘记在组件级别而不是模块级别或全局提供服务:
@Component(
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"],
// declare the provider on a component basis
// so you get a different instance of the service per component
providers: [IdsTrackerService]
)
这是一个带有调试视图的现场演示,用于显示已注册的 ID:https://stackblitz.com/edit/angular-jyvezk
【讨论】:
以上是关于从指令访问外部组件实例的主要内容,如果未能解决你的问题,请参考以下文章