Проекция содержимого: ng-content
Входы передают в компонент данные, но иногда нужно передать целый кусок разметки: заголовок с иконкой, форму, список. Для этого служит проекция содержимого — тег <ng-content> отмечает место, куда Angular вставит всё, что написано между открывающим и закрывающим тегом компонента.
Компонент-обёртка
Сделаем карточку с рамкой и тенью, в которую можно положить что угодно:
ng generate component card<!-- src/app/card/card.html -->
<div class="card">
<ng-content />
</div>/* src/app/card/card.css */
.card {
padding: 16px;
border-radius: 8px;
box-shadow: 0 2px 6px rgb(0 0 0 / 0.15);
}Класс Card в src/app/card/card.ts остаётся пустым — вся работа в шаблоне.
Использование
Родитель импортирует Card и пишет содержимое внутри тега:
<!-- src/app/app.html -->
<app-card>
<h2>Список дел</h2>
<app-todo-list />
</app-card>// src/app/app.ts
import { Component } from '@angular/core';
import { Card } from './card/card';
import { TodoList } from './todo-list/todo-list';
@Component({
selector: 'app-root',
imports: [Card, TodoList],
templateUrl: './app.html',
styleUrl: './app.css',
})
export class App {}Заголовок и список дел окажутся внутри блока с тенью — на месте <ng-content />. Без этого тега содержимое просто не появится на странице.
Несколько слотов
Атрибут select задаёт, какие элементы попадут в данный слот. Значение — CSS-селектор:
<!-- src/app/card/card.html -->
<div class="card">
<header class="card-header">
<ng-content select="[card-title]" />
</header>
<ng-content />
</div><!-- src/app/app.html -->
<app-card>
<h2 card-title>Список дел</h2>
<app-todo-list />
</app-card>Элемент с атрибутом card-title попадёт в шапку карточки, а всё остальное — в слот без select. Атрибут card-title ничего не делает сам — это просто метка для селектора.
Чем отличается от input()
| Способ | Что передаёт | Пример |
|---|---|---|
input() | Данные: строки, числа, объекты | Задача для app-todo-item |
ng-content | Готовую разметку и компоненты | Содержимое карточки |
Компонент с ng-content не знает, что ему положат внутрь, — поэтому он подходит для обёрток: карточек, модальных окон, вкладок.
Частая ошибка
Ждать, что @if вокруг <ng-content /> в дочернем компоненте не даст создать содержимое. Компоненты внутри тега <app-card> создаёт родитель, и они создаются всегда, даже если слот скрыт. Если тяжёлый компонент нужен не всегда, оборачивайте в @if его самого — в шаблоне родителя.