[英]How to get reference to unknown children elements using @ViewChildren
I'm using a third party library that lets me create tabsets. 我正在使用第三方库来创建tabsets。 This is the code I'm using to create a simple tabset
这是我用来创建一个简单的tabset的代码
<clr-tabs
(clrTabsCurrentTabContentChanged)="onTabContentActivated($event)" >
<clr-tab-link>Firewall</clr-tab-link>
<clr-tab-link>DHCP</clr-tab-link>
<clr-tab-content>
<vcd-firewall-tab></vcd-firewall-tab>
</clr-tab-content>
<clr-tab-content>
<vcd-dhcp-tab></vcd-dhcp-tab>
</clr-tab-content>
</clr-tabs>
I have hooked up an event that will tell me when a tab was selected, and I would like to call the loadData()
method on <vcd-firewall-tab>
and <vcd-dhcp-tab>
. 我已经连接了一个事件,告诉我何时选择了一个选项卡,我想在
<vcd-firewall-tab>
和<vcd-dhcp-tab>
上调用loadData()
方法。
The clrTabsCurrentTabContentChanged
will give me a reference to the clr-tab-content
that was selected but I would like to access its first child and call loadData()
to implement lazy loading. clrTabsCurrentTabContentChanged
将为我提供对所选clr-tab-content
的引用,但我想访问它的第一个子loadData()
并调用loadData()
来实现延迟加载。
I think I can use @QueryChildren
annotation, except that I have to specify the type of element to query for. 我想我可以使用
@QueryChildren
注释,除了我必须指定要查询的元素的类型。 The problem is that in this case, I don't know the type, it could be <vcd-firewall-tab>
, <vcd-dhcp-tab>
or the many other tabs that we have and I don't want to add custom code every time I add a new tab. 问题是,在这种情况下,我不知道类型,它可能是
<vcd-firewall-tab>
, <vcd-dhcp-tab>
或我们拥有的许多其他选项卡,我不想添加每次添加新标签时自定义代码。
I was hoping to be able to do something like this from my event handler (but that doesn't exist 我希望能够从我的事件处理程序中做这样的事情(但这不存在
onTabContentActivated(tabContent: TabContent){
(tabContent.query(':first-child') as CanLoadData).loadData();
}
I'm open to any suggestions, I thought maybe I could match the index of the tab to something like @QueryChildren('clr-tab-content > *')
, assuming there's only one child under each tab. 我愿意接受任何建议,我想也许我可以将标签的索引与
@QueryChildren('clr-tab-content > *')
匹配,假设每个标签下只有一个孩子。
There are only two ways supported 只支持两种方式
For other requirements you can inject ElementRef
and access the DOM directly using ElementRef.nativeElement....
but this way you only get the element not components or directives. 对于其他需求,您可以使用
ElementRef.nativeElement....
注入ElementRef
并直接访问DOM ElementRef.nativeElement....
但这样您只能获得元素而不是组件或指令。
The real answer to the question, as mentioned by Günter , is that it can't be done. 正如Günter所提到的 ,这个问题的真正答案是它无法完成。 You cannot query unless you know the type ahead of time.
除非您提前知道类型,否则无法查询。
I hacked a solution to this particular problem minimizing the amount of code to add for each tab by doing two things 我破解了这个特定问题的解决方案,通过做两件事来最小化为每个选项卡添加的代码量
<clr-tab-contents>
. <clr-tab-contents>
的子元素上触发DOM事件。 loadData()
automatically when the tab is activated loadData()
Here's a minimal example that implements that. 这是一个实现它的最小例子。 It's very crude, my real code takes care of other corner cases, but I didn't want to add noise to the solution.
它非常粗糙,我的真实代码处理其他极端情况,但我不想在解决方案中添加噪声。
<!-- One piece of glue per tabset -->
<clr-tabs vcd-lazy-tab-loader>
<clr-tab-link>Firewall</clr-tab-link>
<clr-tab-link>DHCP</clr-tab-link>
<clr-tab-content>
<vcd-firewall-tab></vcd-firewall-tab>
</clr-tab-content>
<clr-tab-content>
<vcd-dhcp-tab></vcd-dhcp-tab>
</clr-tab-content>
</clr-tabs>
// lazy-tab-loader.directive.ts
@Directive({
selector: '[vcd-lazy-tab-loader]'
})
export class VcdLazyTabLoader {
constructor(@Inject(forwardRef(() => Tabs)) private tabSet: Tabs,
private el: ElementRef) {
tabSet.currentTabIndexChanged.subscribe((tabIndex) => {
// Not very pretty, we'll find a nicer way later
// It relies on the internal HTML structure of clr-tab-content
const element = this.el.nativeElement.querySelectorAll(`clr-tab-content`)[tabIndex]
.firstElementChild.firstElementChild;
element.dispatchEvent(new CustomEvent("vcd-activated", {}));
});
}
}
export interface CanLoadData {
loadData(): void;
}
export function setupLazyLoader(el: HTMLElement, dataLoader: CanLoadData) {
el.addEventListener('vcd-activated', () => {
dataLoader.loadData();
});
}
// firewall-tab.component.ts (AND dhcp-tab.components.ts)
@Component(...)
// First piece of glue (implement CanLoadData) for a tab
class FirewallTab implements CanLoadData {
constructor(private firewallService: FirewallService,
private el: ElementRef) {
// Second piece of glue, per tab
// Constructor is not the best place, it's here just to avoid extra code
setupLazyLoader(el.nativeElement, this);
}
loadData () {
this.service.getRules().subscribe((data)=> this.rules = rules);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.