Перевод статьи с официального сайта документации Angular
Довольно часто нужно создавать компоненты, которые служат в качестве контейнера для различного типа контета. Например, вы хотите создать камстомный компонент карточку (CustomCard):
@Component({
selector: 'custom-card',
template: '<div class="card-shadow"> <!-- card content goes here --> </div>',
})
export class CustomCard {/* ... */}
Вы можете использовать <ng-content> элемент в качестве метки, которая укажет на местоположение вашего будущего контента.
@Component({
selector: 'custom-card',
template: '<div class="card-shadow"> <ng-content></ng-content> </div>',
})
export class CustomCard {/* ... */}
<aside> ?
<ng-content> работает аналогично нативному компоненту <slot> , но с некоторой Angular-специфичной функциональностью.
</aside>
Когда вы используете компонент совместно с <ng-content> , любой дочерний компонент хост-компонента будет рендериться (отображаться), или по-другому проецироваться, в местоположение <ng-content> :
// Компонент источник
@Component({
selector: 'custom-card',
template: `
<div class="card-shadow">
<ng-content />
</div>
`,
})
export class CustomCard {/* ... */}
<!-- Использование компонента -->
<custom-card>
<p>This is the projected content</p>
</custom-card>
<!-- отрендеренный DOM -->
<custom-card>
<div class="card-shadow">
<p>This is the projected content</p>
</div>
</custom-card>
Angular относится к любому дочернему компоненту, переданному таким путем, как к содержимому ****компонента. Это отличается от представления компонента, которое относится к элементам, определенным в шаблоне этого компонента.
<ng-content> элемент не является ни компонентом, ни DOM элементом. Напротив, это специальная метка или указатель, который указывает Angular, где ему необходимо отрендерить контент. Компилятор Angular обрабатывает все элементы <ng-content> во время сборки. Вы не сможете вставить, удалить или изменить <ng-content> во время выполнения (в режиме реального времени). Вы не можете добавить директивы, стили или произвольные атрибуты в <ng-content> .
<ng-content> не подходит для использования с условиями через @if, @for, или @switch . Angular в любом случае создает экземпляры и DOM - ноды для контента, отрендеренного с помощью метки <ng-content> , даже в тех ситуациях, когда <ng-content> скрыт. Для условного рендеринга контента больше подходит ng-template.
Множественное отображение контента
Angular поддерживает отображение нескольких элементов с помощью нескольких <ng-content> меток (плейсхолдеров), используя CSS-селекторы. Расширив пример карточки выше, вы можете создать два плейсхолдера для заголовка и тела, используя атрибут select :
<!-- Шаблон компонента -->
<div class="card-shadow">
<ng-content select="card-title"></ng-content>
<div class="card-divider"></div>
<ng-content select="card-body"></ng-content>
</div>
<!-- Использование компонента -->
<custom-card>
<card-title>Hello</card-title>
<card-body>Welcome to the example</card-body>
</custom-card>
<!-- отрендеренный(сгенерированный) DOM -->
<custom-card>
<div class="card-shadow">
<card-title>Hello</card-title>
<div class="card-divider"></div>
<card-body>Welcome to the example</card-body>
</div>
</custom-card>
<ng-content> поддерживает те же CSS-селекторы, что и компоненты.
Если вы используете один или более <ng-content> с select атрибутом и один <ng-content> без атрибута, то последний из них (<ng-content> без атрибута) будет отображать все элементы, которые не совпадают по заданному select атрибуту:
<!-- Шаблон компонента -->
<div class="card-shadow">
<ng-content select="card-title"></ng-content>
<div class="card-divider"></div>
<!-- отображаем все здесь, исключая "card-title" -->
<ng-content></ng-content>
</div>
<!-- Использование компонента -->
<custom-card>
<card-title>Hello</card-title>
<img src="..." />
<p>Welcome to the example</p>
</custom-card>
<!-- Срендеренный DOM -->
<custom-card>
<div class="card-shadow">
<card-title>Hello</card-title>
<div class="card-divider"></div>
<img src="..." />
<p>Welcome to the example></p>
</div>
</custom-card>
Если компонент не включает в себя <ng-content> без атрибута select, то любые элементы, которые не имеют соответствия с одной из меток <ng-content> компонента с атрибутом, в конечном итоге не будут отрендерены DOM. c
Контент по-умолчанию
Angular обладает возможностью отображать контент по-умолчанию для <ng-content> компонента на случай, если компонент не имеет никакого подходящего содержимого (дочернего контента). Вы можете определить контент по-умолчанию добавив дочерний контент внутрь элемента <ng-content> самостоятельно.
<!-- Шаблон компонента -->
<div class="card-shadow">
<ng-content select="card-title">Default Title</ng-content>
<div class="card-divider"></div>
<ng-content select="card-body">Default Body</ng-content>
</div>
<!-- Использование компонента -->
<custom-card>
<card-title>Hello</card-title>
<!-- No card-body provided -->
</custom-card>
<!-- Генерация DOM -->
<custom-card>
<div class="card-shadow">
Hello
<div class="card-divider"></div>
Default Body
</div>
</custom-card>
Именование контента для проецирования
Angular поддерживает специальный атрибут ngProjectAs, который указать вам на CSS-селектор для любого элемента. Каким бы ни был элемент с указанным атрибутом ngProjectAs для передачи в <ng-content>, Angular сравнит значение атрибута select со значением ngProjectAs , а не будет пытаться идентифицировать элемент через тег.
<!-- Шаблон компонента -->
<div class="card-shadow">
<ng-content select="card-title"></ng-content>
<div class="card-divider"></div>
<ng-content></ng-content>
</div>
<!-- Использование компонента -->
<custom-card>
<h3 ngProjectAs="card-title">Hello</h3>
<p>Welcome to the example</p>
</custom-card>
<!-- Генерация DOM -->
<custom-card>
<div class="card-shadow">
<h3>Hello</h3>
<div class="card-divider"></div>
<p>Welcome to the example></p>
</div>
</custom-card>
ngProjectAs поддерживает только статические значения и не может принимать динамические выражения.