So I'm trying to display child ponents at specific locations in my Component.
I have the following:
@Component({
selector: 'app-item-list',
template: `
<p *ngFor="let item of items">
{{item.order}}
<!-- display content of child ponent here -->
</p>`
})
export class ItemListComponent implements OnInit, AfterContentInit {
//Get all child ponents of the type ItemComponent and store them.
@ContentChildren(ItemComponent, {descendants: true})
items?: QueryList<ItemComponent>;
constructor() { }
ngOnInit() {
}
ngAfterContentInit(): void {
}
}
@Component({
selector: 'app-item',
template: `
<p>
item works!
</p>
<ng-content></ng-content>
`
})
export class ItemComponent implements OnInit {
@Input() order?: string;
constructor() { }
ngOnInit() {
}
}
I tried to display it using <ng-content select="item">
but that didn't work.
With the following:
<app-item-list>
<app-item order="2">
test2
</app-item>
<app-item order="1">
test1
</app-item>
</app-item-list>
the expected output is
2
item works!
test2
1
item works!
test1
So I'm trying to display child ponents at specific locations in my Component.
I have the following:
@Component({
selector: 'app-item-list',
template: `
<p *ngFor="let item of items">
{{item.order}}
<!-- display content of child ponent here -->
</p>`
})
export class ItemListComponent implements OnInit, AfterContentInit {
//Get all child ponents of the type ItemComponent and store them.
@ContentChildren(ItemComponent, {descendants: true})
items?: QueryList<ItemComponent>;
constructor() { }
ngOnInit() {
}
ngAfterContentInit(): void {
}
}
@Component({
selector: 'app-item',
template: `
<p>
item works!
</p>
<ng-content></ng-content>
`
})
export class ItemComponent implements OnInit {
@Input() order?: string;
constructor() { }
ngOnInit() {
}
}
I tried to display it using <ng-content select="item">
but that didn't work.
With the following:
<app-item-list>
<app-item order="2">
test2
</app-item>
<app-item order="1">
test1
</app-item>
</app-item-list>
the expected output is
2
item works!
test2
1
item works!
test1
https://stackblitz./edit/angular-ivy-2aibgt
Share Improve this question edited Jul 30, 2020 at 21:01 Peter asked Jul 16, 2020 at 17:00 PeterPeter 38.6k39 gold badges150 silver badges209 bronze badges4 Answers
Reset to default 9 +100I can suggest you a solution that is used in Angular material library.
- Wrap content of
app-item
ponent in<ng-template>
tag
item.ponent.html
<ng-template> <----------------------------- wrapper
<p>
item works!
</p>
<ng-content></ng-content>
</ng-template>
- then we can grab a reference to that
TemplateRef
item.ponent.ts
@ViewChild(TemplateRef, {static: true}) template: TemplateRef<any>;
- finally we can use it in a loop of
app-item-list
ponent
item-list.ponent.html
<p *ngFor="let item of items">
{{item.order}}
<ng-template [ngTemplateOutlet]="item.template"></ng-template>
</p>
Forked Stackblitz
There is really no way to achieve this using ng-content
(as far as I know).
ng-content
is for static content projection only.
Have a look at the use case here - https://github./angular/angular/issues/8563 - paragraph 2 confirms the fact that you have to use a query with viewref to do what you want to do i.e. the solution that @yurzui provided.
You can always use the selector to statically select which part of the content you want to project, but I suspect this is not what you're looking for:
<ng-content select="[order=2]">
</ng-content>
<ng-content select="[order=1]">
</ng-content>
You may missed add select
item reference variable in item-list.ponent.html
item.ponent.html
<p>item works</p>
<ng-content select="[body]">
</ng-content>
item-list.ponent.html
<p *ngFor="let item of items">
<app-item >
<div body>
{{item.order}}
</div>
</app-item>
test2
</p>
Ref: Stackblitz example
Take a look at this. Ealier I thought there was not way to achieve your output but I finally figured it out.
What I did was eliminate the @ContentChildren
approach and instead replaced it with an items Input
passed from the app
ponent. I iterated through the items, displaying the order and the corresponding app-item
ponent.