Множественный нг-контент

95

Я пытаюсь создать собственный компонент, используя несколько ng-contentв Angular 6, но это не работает, и я понятия не имею, почему.

Это код моего компонента:

<div class="header-css-class">
    <ng-content select="#header"></ng-content>
</div>
<div class="body-css-class">
    <ng-content select="#body"></ng-content>
</div>

Я пытаюсь использовать этот компонент в другом месте и сделать два различных HTML кода bodyи заголовок selectиз ng-content, что - то вроде этого:

<div #header>This should be rendered in header selection of ng-content</div>
<div #body>This should be rendered in body selection of ng-content</div>

Но компонент отображается пустым.

Вы, ребята, знаете, что я делаю неправильно или как лучше всего отрендерить два разных раздела в одном компоненте?

Благодарность!

Лукас Сантос
источник
К сожалению, stackoverflow не сохранил мой второй фрагмент кода: код, который я использую в компоненте, выглядит примерно так: <div #header> Это содержимое заголовка </div> <div #body> Это содержимое тела </div>
Лукас Сантос,

Ответы:

179
  1. Вы можете добавить фиктивные атрибуты headerи bodyвместо ссылок на шаблоны (#header, #body).
  2. И включить использование ng-contentс selectатрибутом вроде select="[header]".

app.comp.html

<app-child>
    <div header >This should be rendered in header selection of ng-content</div>
    <div body >This should be rendered in body selection of ng-content</div>
</app-child>

child.comp.html

<div class="header-css-class">
    <ng-content select="[header]"></ng-content>
</div>
<div class="body-css-class">
    <ng-content select="[body]"></ng-content>
</div>

ДЕМО

Амит Чигадани
источник
6
Если вы не хотите отображать дополнительный div или какой-либо другой тег, вы должны использовать <ng-container>
sobczi
3
@AmitChigadani Я считаю, что @sobczi означает, что вы можете заменить <div header>на <ng-container header>.
user12893298320392
3
Подтверждаю замену <div header>с <ng-container header>работой тоже.
Азерафати
49

Чтобы соответствовать спецификациям веб-компонентов . Даже если это Angular. Речь идет об избежании атрибутов для селектора, таких как директивы Angular или зарезервированных атрибутов с другим использованием. Итак, мы просто используем атрибут «слот». Посмотрим <ng-content select="[slot=foobar]">как <slot name="foobar">.

Пример:

hello-world.component.html

<ng-content select="[slot=start]"></ng-content>
<span>Hello World</span>
<ng-content select="[slot=end]"></ng-content>

app.component.html

<app-hello-world>
  <span slot="start">This is a </span>
  <span slot="end"> example.</span>
</app-hello-world>

Результат

This is a Hello World example.

Пример Stackblitz

Вы можете использовать любое имя, например «банан» или «рыба». Но «начало» и «конец» являются хорошим условием для размещения элементов до и после.

Доминик
источник
Как я могу запросить эти элементы? со слотом имени.
Nexeuz,
Это зависит от ваших настроек Angular и компонентов, а также от того, что вы конкретно хотите. Вы можете использовать ViewChild в TS или :hostи ::ng-deepв SCSS. Но это всего лишь пример. См. Stackblitz. Может быть, ::slotted/ ::contentтоже будет работать. Но не уверен. В сети будет больше информации по этой теме. Обычно вы должны стилизовать только сам компонент. И избегайте внешнего стиля (глобального). В противном случае у вас будут нежелательные побочные эффекты.
Доминик
Хорошая практика - обернуть его. См. Обновленный пример Stackblitz в моем последнем комментарии. См. Файлы html и css компонента. Вы должны предпочесть это ng-deep. Например, <div class="end"><ng-content></ng-content></div>потому что этот элемент доступен в компоненте. Ng-content - это просто псевдоэлемент, который заменяется закрепленным снаружи элементом. Поэтому вам нужно использовать селектор ng-deep.
Доминик
9

в качестве альтернативы вы можете использовать:

app.comp.html

<app-child>
    <div role="header">This should be rendered in header selection of ng-content</div>
    <div role="body">This should be rendered in body selection of ng-content</div>
</app-child>

child.comp.html

<div class="header-css-class">
    <ng-content select="div[role=header]"></ng-content>
</div>
<div class="body-css-class">
    <ng-content select="div[role=body]"></ng-content>
</div>
Анджело Радичи
источник
4

Дополняя другие ответы:

Вы также можете сделать это с помощью пользовательских тегов (например <ion-card>, <ion-card-header>и <ion-card-content>).

app.comp.html

<app-child>
    <app-child-header>This should be rendered in header selection of ng-content</app-child-header>
    <app-child-content>This should be rendered in content selection of ng-content</app-child-content>
</app-child>

child.comp.html

<div class="header-css-class">
    <ng-content select="app-child-header"></ng-content>
</div>
<div class="content-css-class">
    <ng-content select="app-child-content"></ng-content>
</div>

Вы получите предупреждающее сообщение, но оно будет работать. Вы можете подавить предупреждающие сообщения или использовать известные теги, такие как headerили footer. Однако, если вам не нравится какой-либо из этих методов, вы должны выбрать одно из других решений.

Уэсли Гонсалвеш
источник