Angular 8: как использовать слот Multi-Content-Projection / Multiple-Transclusion дважды?
- У меня есть проект Angular 8.2 с двумя разными режимами отображения (пейзаж | портрет)
- И в каждом из них есть панель инструментов вверху и внизу, окружающая основной контент.
- В
menu
а также основныеcontent
зависит от модуля, поэтому я использую слоты. Другими словами: один из 5 различных возможных родительских компонентов использует этот компонент и предоставляетmain
содержание и (индивидуально разные)menu
, используя угловую проекцию контента.
<ng-template #menu><ng-content select="[slot='menu']"></ng-content></ng-template>
<ng-template #content><ng-content select="[slot='content']"></ng-content></ng-template>
<section *ngIf="landscape">
<div class="global-ui-top">
<ng-container *ngTemplateOutlet="menu"></ng-container> // 1st
</div>
<some-main-content>
<ng-container *ngTemplateOutlet="content"></ng-container>
</some-main-content>
<div class="global-ui-bottom">
<ng-container *ngTemplateOutlet="menu"></ng-container> // 2nd
</div>
</section>
// portrait mode
<section *ngIf="!landscape">
... pretty similar to above, also 2× menu, 1× content...
Проблема: как я могу использовать слот дважды?** Ошибка не возникает, если я использую, например..
A <ng-container *ngTemplateOutlet="menu"></ng-container> A
B <ng-container *ngTemplateOutlet="menu"></ng-container> B
... однако слот "выбирается один раз" в последний раз (тег между двумя буквами A остается пустым). Другими словами, мой 1-й.global-ui-top
остается пустым.
nb: Этоng-detour
в строке 1+2 помогает обойти определенную ошибку. Это не причиняет вреда, но и не помогает (к сожалению,ng-template
-содержание не замораживается после "первого заполнения"). Видимо, в отношении слотов существует принцип "уникальности в выборе".
Есть ли способ вставить содержимое слота меню в шаблон любого типа и повторно использовать его несколько раз (все видимые одновременно)?**
- возможно причудливый флаг на любом
<ng-content>
или<ng-template
? ("статический"?!?) - или сначала каким-то образом сбить содержимое слота в
@viewChild()
(в component.ts)... - еще...?
незначительное обновление
Кажется возможным захватить ссылку ng-template в View Child:
@ViewChild('menu', {static: true}) menuA: TemplateRef<any>;
... а console.dir()
показывает мне действительный ElementRef, но мне не удается вывести его в.html-шаблоне, т.е. <ng-template [ngTemplateOutlet]="menuA"></ng-template>
1 ответ
Может быть, этот доклад будет полезным.
Насколько я понимаю, ng-content
это не создает контент, он просто перемещает содержимое из одной части в другую.
Я думаю, решение вашей проблемы - использовать ng-template
. Например:
projected.component.ts
let instances = 0;
@Component({
selector: 'app-projected',
template: `projected instance nr: {{ instanceId }}`
})
export class ProjectedComponent implements OnInit {
instanceId: number;
constructor() { }
ngOnInit() {
this.instanceId = ++instances;
}
}
parent.component.ts
@Component({
selector: 'app-parent',
template: `
<h3>Parent component</h3>
<p>Using content #1</p>
<ng-container *ngTemplateOutlet="content"></ng-container>
<p>Using content #2</p>
<ng-container *ngTemplateOutlet="content"></ng-container>
`,
})
export class ParentComponent implements OnInit {
@ContentChild('content', { read: TemplateRef }) content: TemplateRef<any>;
constructor() { }
ngOnInit() {
}
}
И вот что важно:
<app-parent>
<ng-template #content>
<app-projected></app-projected>
</ng-template>
</app-parent>
Насколько я понимаю, что внутри ng-template
можно рассматривать как план. Поэтому каждый раз, когда вы используетеng-template
, вы создадите новый экземпляр этого чертежа.