@ContentChildren未在自定义组件中拾取物品

时间:2018-12-06 06:26:34

标签: angular angular-decorator

我正在尝试使用@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来演示这一点。

3 个答案:

答案 0 :(得分:4)

似乎不是通过github来解决该问题的时间表...我还找到一条评论,指出您无法跨越ng-content边界进行查询。

https://github.com/angular/angular/issues/14320#issuecomment-278228336

以下是可能的解决方法,以使元素从OptionPickerComponent中冒出来。


enter image description here


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

https://stackblitz.com/edit/angular-popup-child-selection-issue-bjhjds?embed=1&file=src/app/option-picker/option-picker.component.ts

答案 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]