@ContentChild 裝飾器

基本概念

當元件的模板使用 <ng-content> 進行內容投影時,被投影的內容實際上不是該元件模板的一部分。這時 @ViewChild / @ViewChildren 無法選擇這些投影內容,需要使用 @ContentChild / @ContentChildren 來訪問投影內容中的元素。

@ViewChild 與 @ContentChild 的區別

  • @ViewChild:選擇元件自身模板中的元素

  • @ContentChild:選擇投影到元件中的內容元素

基本語法

@ContentChild(selector, { static?: boolean }) name: ElementRef<Type>;
  • selector:可以是 component、directive、template reference variable(字串)或 TemplateRef

  • static:可選參數,決定查詢結果什麼時候解析

    • static: true - 在 ngOnInit 中可用

    • static: false(默認值)- 在 ngAfterContentInit 中可用

  • name:元件類中用來存儲查詢結果的屬性名

  • Type:選擇器獲取的元素類型

使用範例

假設有以下元件結構:

control.component.html(父元件)

<label>{{ label }}</label>
<ng-content select="input, textarea" />

new-ticket.component.html(使用父元件的元件)

<form (ngSubmit)="onSubmit(titleInput.value, textInput.value)" #form>
  <app-control label="Title">
    <input name="title" id="title" #titleInput #input/>
  </app-control>
  <app-control label="Request">
    <textarea name="request" id="request" rows="3" #textInput #input></textarea>
  </app-control>
  <p>
    <button appButton>
      Submit
      <span ngProjectAs="icon">⌲</span>
    </button>
  </p>
</form>

control.component.ts(父元件)

@ContentChild('input') private control?: ElementRef<HTMLInputElement | HTMLTextAreaElement>;

生命週期注意事項

@ContentChild 引用的元素在 ngAfterContentInit 生命週期鉤子中可用:

typescriptCopyngAfterContentInit() {
  // 這裡可以安全地訪問 ContentChild 元素
  if (this.control) {
    console.log(this.control.nativeElement);
  }
}

Angular 17+ 函數式寫法

在 Angular 17+ 中,也提供了函數式寫法:

private control = contentChild<ElementRef<HTMLInputElement | HTMLTextAreaElement>>('input');

重要注意事項:

  • 一個模板中可以有多個相同的模板變量,也可以對一個元素添加多個模板變量

  • 使用 @ContentChild 而非 @ContentChildren 是因為這個例子中每個 app-control 元件實例只獲取第一個 input 或 textarea

  • <ng-content>select 屬性可以使用 CSS 選擇器指定要投影的內容

  • ngProjectAs 屬性可以指定元素如何被 <ng-content> 的選擇器匹配(如範例中的 <span ngProjectAs="icon">⌲</span>

Last updated