menu
as well as the main content
is module specific, thus I am using slots. In other words: One out of 5 different possible parent component uses this component and provides the main
content and an (individually different) menu
, using angular content projection. <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
...however the slot get's only "picked once" on last occasion (the tag between the two A's remains empty). In other words, my 1st .global-ui-top
remains empty.
nb: This ng-detour
in line 1+2 helps around a certain bug. Is is not doing harm, but also not helping (sadly the ng-template
-contents don't get frozen after “first fill” ). Apparently there is a „uniqueness in the selection“ principle regarding slots.
<ng-content>
or <ng-template
? ("static"?!?)@viewChild()
(in component.ts)...minor update
It seems possible to capture the ng-template reference into a View Child:
@ViewChild('menu', {static: true}) menuA: TemplateRef<any>;
...a console.dir()
shows me a valid ElementRef, but I don't manage to output that in the .html-Template, i.e. <ng-template [ngTemplateOutlet]="menuA"></ng-template>
Maybe this talk is going to be useful.
My understanding is that ng-content
does not create content, it simply moves content from one part to another.
I think the solution to your problem is to use ng-template
. For example:
let instances = 0;
@Component({
selector: 'app-projected',
template: `projected instance nr: {{ instanceId }}`
})
export class ProjectedComponent implements OnInit {
instanceId: number;
constructor() { }
ngOnInit() {
this.instanceId = ++instances;
}
}
@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() {
}
}
And here's the important thing:
<app-parent>
<ng-template #content>
<app-projected></app-projected>
</ng-template>
</app-parent>
As far as I understand, what's inside an ng-template
can be thought of as a blueprint. So every time you use ng-template
, you'd create a new instance of that blueprint.