Angular: динамические компоненты и проекция контента

ViewEncapsulation

Определяет, будут ли стили компонента влиять на всё приложение:

  • Emulated (по умолчанию) — стили компонента изолированы через эмуляцию (атрибуты); внешние стили могут проникать.
  • ShadowDom — настоящая изоляция через Shadow DOM; внешние стили не проникают. (Старое значение Native удалено в Angular 11.)
  • None — стили компонента видны всем компонентам приложения.

Content Projection и ng-content

Паттерн, при котором контент вставляется (проецируется) внутрь другого компонента через <ng-content> — плейсхолдер (слот) для контента родителя.

<ng-content select="..."> — именованный слот: выборочно проецирует контент в конкретные слоты.

<!-- родитель -->
<app-child>
  <div slot="header">Header</div>
  <div slot="content">Content</div>
</app-child>
 
<!-- child -->
<ng-content select="[slot=header]"></ng-content>
<ng-content select="[slot=content]"></ng-content>
  • @ContentChild — ссылка на один спроецированный элемент/компонент/директиву/шаблон.
  • @ContentChildren — коллекция спроецированных элементов, подходящих под селектор.

ViewContainerRef и TemplateRef

  • ViewContainerRef — контейнер, куда можно динамически вставлять и удалять view (компоненты, шаблоны). Обычно получают через @ViewChild(..., { read: ViewContainerRef }).
  • TemplateRef — представляет встроенный шаблон (<ng-template>). Вместе с ViewContainerRef.createEmbeddedView() создаёт и вставляет динамические view.
@ViewChild("container", { read: ViewContainerRef }) container!: ViewContainerRef;
@ViewChild("tpl", { read: TemplateRef }) tpl!: TemplateRef<any>;
 
embed() {
  this.container.createEmbeddedView(this.tpl);
}

Проброс контекста в шаблон через ngTemplateOutlet:

<div *ngFor="let item of items"
     [ngTemplateOutlet]="itemTpl"
     [ngTemplateOutletContext]="{ $implicit: item }"></div>
 
<ng-template #itemTpl let-item>{{ item }}</ng-template>

ngComponentOutlet

Директива для динамического рендеринга компонента по его типу — создаёт и вставляет компонент в DOM на основе условий времени выполнения.

<ng-container *ngComponentOutlet="dynamicComponent"></ng-container>