錯誤百科

控制流程阻礙內容投影

控制流程區塊內的元素或 <ng-template> 本應被投影到特定的 <ng-content> 插槽,但因為該區塊有不止一個根節點而沒有被投影。

import {Component} from '@angular/core';

@Component({
  selector: 'app-card',
  template: `
    <ng-content select="[card-title]" />
    <ng-content />
  `,
})
class Card {}

@Component({
  imports: [Card],
  // NG8011: <h2 card-title> is not projected into the "[card-title]" slot because the @if
  // block has two root nodes (the h2 and the p).
  template: `
    <app-card>
      @if (showTitle) {
        <h2 card-title>Title</h2>
        <p>Subtitle</p>
      }
    </app-card>
  `,
})
class MyComponent {
  showTitle = true;
}

除錯方式

控制流程區塊模擬 *ngIf 與 *ngFor 的內容投影行為,它們會投影套用到它們身上的元素。 這只有在區塊具有單一根節點時才有效。 當區塊有不止一個根節點時,Angular 無法用該元素來選擇插槽,因此 <h2 card-title> 最終會進入 Card 的預設 <ng-content /> 插槽,而不是 [card-title] 插槽。

文字也算根節點,所以被投影元素旁邊多出一行文字會造成相同問題,除非包含該區塊的元件設定了 preserveWhitespaces: true,在此情況下空白字元也算數。

要解決此錯誤,請挑選以下其中一種方式:

  • 把內容包在 <ng-container> 中,並使用 ngProjectAs 來符合插槽的選擇器。容器內的所有內容都會被投影到該插槽。

    @Component({
      imports: [Card],
      template: `
        <app-card>
          @if (showTitle) {
            <ng-container ngProjectAs="[card-title]">
              <h2>Title</h2>
              <p>Subtitle</p>
            </ng-container>
          }
        </app-card>
      `,
    })
    class MyComponent {
      showTitle = true;
    }
  • 把內容拆到多個區塊中,讓每個區塊的根部都有單一可投影節點。

    @Component({
      imports: [Card],
      template: `
        <app-card>
          @if (showTitle) {
            <h2 card-title>Title</h2>
          }
          @if (showTitle) {
            <p>Subtitle</p>
          }
        </app-card>
      `,
    })
    class MyComponent {
      showTitle = true;
    }