我有一个需要帮助的复杂场景。
我有一个指令(称为TagDirective
),它放在我的应用程序的多个元素上。我有另一个指令(QueryDirective
),它需要引用其主机元素上存在的TagDirective
的所有实例,以及层次结构中它上面的所有元素。
示例:
<div appTag="a">
<div appTag="b">
<div appTag="c">
<div appTag="d">
<div appQuery>
<!-- In here I want to have a reference to TagDirectives instances
d,c,b,a -->
</div>
</div>
</div>
<div appTag="e">
<div appTag="f">
<div appTag="g">
<div appTag="h">
<div appQuery>
<!-- In here I want to have a reference to TagDirectives instances
h,g,f,e,b,a -->
</div>
</div>
</div>
<div appQuery>
<!-- In here I want to have a reference to TagDirectives instances
f,e,b,a -->
</div>
</div>
</div>
</div>
</div>
我知道我可以通过让注入器在TagDirective
的构造函数中提供它来单独获取对host元素的QueryDirective
的引用,我也知道我可以通过注入获得下一个更高的实例ViewContainerRef
并使用其parentInjector
成员请求TagDirective
类型的实例。
但是,我还没有找到进一步推进树的方法,并将所有实例一直收集到根目录。
我将如何实现这一目标?谢谢!
答案 0 :(得分:6)
由于每个元素都有自己的注入器,我们不能只使用multi: true
它只有在我们在同一个元素上提供相同的标记时才会起作用。
可能的解决方法如下:
export const TAG_DIRECTIVES_TOKEN = new InjectionToken('tags directives');
export function tagDirectiveFactory(dir: TagDirective, token: TagDirective[]) {
return token ? [dir, ...token] : [dir];
}
@Directive({
selector: '[appTag]',
providers: [{
provide: TAG_DIRECTIVES_TOKEN,
useFactory: tagDirectiveFactory,
deps: [TagDirective, [ new SkipSelf(), new Optional(), TAG_DIRECTIVES_TOKEN ]]
}]
})
export class TagDirective {}
@Directive({
selector: '[appQuery]'
})
export class AppQueryDirective {
constructor(@Inject(TAG_DIRECTIVES_TOKEN) private directives: TagDirective[]){
console.log(directives);
}
}
<强> Stackblitz Example 强>
在上面的代码中,我在每个TAG_DIRECTIVES_TOKEN
元素上提供div[appTag]
。我使用具有以下依赖项的工厂:
deps: [TagDirective, [ new SkipSelf(), new Optional(), TAG_DIRECTIVES_TOKEN ]]
^^^^^ ^^^^^
current instance of TagDirective parent optional TAG_DIRECTIVES_TOKEN
其中:
SkipSelf
告诉角度编译器跳过当前令牌并使用我们在父div[appTag]
中提供的令牌
Optional
,因为root div[appTag]
元素无法识别父TAG_DIRECTIVES_TOKEN
,因此有角度的编译器不会引发错误:
没有提供的InjectionToken标记指令!