我正在尝试使用@ContentChildren
来拾取带有#buttonItem
标签的所有物品。
@ContentChildren('buttonItem', { descendants: true })
当我们在父组件中直接具有ref项目时,此方法有效。
<!-- @ContentChildren returns child item -->
<parent-component>
<button #buttonItem></button>
<parent-component>
但是,如果将带有#buttonItem
引用的元素包装在自定义组件中,则即使设置了@ContentChildren
选项,{descendants: true}
也不会被选择。
<!-- @ContentChildren returns empty -->
<parent-component>
<child-component-with-button-ref></child-component-with-button-ref>
<parent-component>
我创建了一个简单的StackBlitz example来演示这一点。
答案 0 :(得分:4)
似乎不是通过github来解决该问题的时间表...我还找到一条评论,指出您无法跨越ng-content边界进行查询。
https://github.com/angular/angular/issues/14320#issuecomment-278228336
以下是可能的解决方法,以使元素从OptionPickerComponent
中冒出来。
在OptionPickerComponent
中计数#listItem
并发出数组AfterContentInit
@Output() grandchildElements = new EventEmitter();
@ViewChildren('listItem') _items
ngAfterContentInit() {
setTimeout(() => {
this.grandchildElements.emit(this._items)
})
}
设置模板引用#picker
,注册到(grandchildElements)
事件,并将$event
设置为picker.grandchildElements
<app-option-picker #picker [optionList]="[1, 2, 3]" (grandchildElements)="picker.grandchildElements = $event" popup-content>
在PopupComponent
上创建输入以接受来自picker.grandchildElements
的值
@Input('grandchildElements') grandchildElements: any
在app.component.html
中接受picker.grandchildElements
作为输入
<app-popup [grandchildElements]="picker.grandchildElements">
popup.component
设置console.log
用于打开和关闭
open() {
if (this.grandchildElements) {
console.log(this.grandchildElements);
}
else {
console.log(this.childItems);
}
close() {
if (this.grandchildElements) {
console.log(this.grandchildElements);
}
else {
console.log(this.childItems);
}
popup.component
将您的ContentChildren
改回listItem
@ContentChildren('listItem', { descendants: true }) childItems: Element;
popup.component.html
设置标头表达式
<h3>Child Items: {{grandchildElements ? grandchildElements.length : childItems.length}}</h3>
Stackblitz
答案 1 :(得分:1)
我有同样的问题。我们将Kendo组件用于角度。需要将Columns定义为Grid组件的ContentChilds。当我想将其包装到自定义组件中并尝试通过ng-content提供其他列时,它根本无法工作。
我设法通过重置自定义包装组件的网格组件AfterViewInit的QueryList使其工作。
@ViewChild(GridComponent, { static: true })
public grid: GridComponent;
@ContentChildren(ColumnBase)
columns: QueryList<ColumnBase>;
ngAfterViewInit(): void {
this.grid.columns.reset([...this.grid.columns.toArray(), ...this.columns.toArray()]);
this.grid.columnList = new ColumnList(this.grid.columns);
}
答案 2 :(得分:0)
一个选项是重新绑定到内容子级。
在要添加要拾取的内容子级的模板中:
<outer-component>
<content-child [someBinding]="true" (onEvent)="someMethod($event)">
e.g. inner text content
</content-child>
</outer-component>
在虚构的示例<outer-component>
中:
@Component()
class OuterComponent {
@ContentChildren(ContentChild) contentChildren: QueryList<ContentChild>;
}
,以及用于<outer-component>
的模板,其中添加了<content-child>
组件,并重新绑定到该组件:
<inner-template>
<content-child
*ngFor="let child of contentChildren?.toArray()"
[someBinding]="child.someBinding"
(onEvent)="child.onEvent.emit($event)"
>
<!--Here you'll have to get the inner text somehow-->
</content-child>
</inner-template>
根据您的情况,获取内部文本可能是不可能的。如果您完全控制虚构的<content-child>
组件,则可以公开访问元素ref:
@Component()
class ContentChildComponent {
constructor(public element: ElementRef<HTMLElement>)
}
然后重新绑定它时,可以添加[innerHTML]
绑定:
<content-child
*ngFor="let child of contentChildren?.toArray()"
[someBinding]="child.someBinding"
(onEvent)="child.onEvent.emit($event)"
[innerHTML]="child.element.nativeElement.innerHTML"
></content-child>
但是,您可能必须sanitize the input到[innerHTML]
。