I have such nested ng-template
structure.
@Component({
selector: 'my-app',
template: `
<list>
<ng-template *ngFor="let item of Items" #ListItem>
<ng-template #ListItemLine>{{ item[0] }}</ng-template>
<ng-template #ListItemLine>{{ item[1] }}</ng-template>
<ng-template #ListItemLine>{{ item[2] }}</ng-template>
I can see this line, but can't get above templates
</ng-template>
</list>
`,
})
export class App {
Items: Array<Array<string>> = [
[ "1-1", "1-2", "1-3", ],
[ "2-1", "2-2", "2-3", ],
[ "3-1", "3-2", "3-3", ],
[ "4-1", "4-2", "4-3", ],
[ "5-1", "5-2", "5-3", ],
]
}
How can I render children ng-component
in my component:
@Component({
selector: 'list',
template: `
<ul>
<li *ngFor="let item of Items">
<ng-container *ngTemplateOutlet="item"></ng-container>
</li>
</ul>
`,
})
export class ListComponent {
@ContentChildren('ListItem') public Items;
}
Plunkr https://plnkr.co/edit/Hi1ZqPAAYyIbclUuzRrl?p=preview
Thank you in advance.
Update
At the end I want to wrap Angular Material components into my components, so if I would find a btter UI than Material, I shouldn't have to change all accurances of Material components in my program, I would just need to change implementation of my wrapper UI components.
For exmple let's try to wrap mat-list
component. I need to make a wrapper for mat-list
container, let's call it my-list
:
@Component({
selector: 'my-list',
template: `
<mat-list>
<ng-content></ng-content>
</mat-list>
`,
})
and a wrapper for mat-list-item
:
@Component({
selector: 'my-list-item',
template: `
<mat-list-item>
<ng-content></ng-content>
</mat-list>
`,
})
The HTML render result would be:
Each Material component surrounded by my wrapper, so directives and styles which come with Material will not work.
Here is how I would solve this based on the information you provided. As you already suggested I have made two components list
and list-item
.
The list component renders the list-item
components based on an input array and the content of the list component must contain a template that defines the list item template. Sample code:
@Component({
selector: 'list',
template: `
<ul>
<list-item *ngFor="let item of items" [data]="item" [itemTemplate]="itemTemplate"></list-item>
<ng-content></ng-content>
</ul>
`,
})
export class ListComponent {
@ContentChild(TemplateRef)
public itemTemplate: TemplateRef;
@Input()
public items: any[];
}
Then the list-item
component just renders the list item template provided in the a container element. Sample code:
@Component({
selector: 'list-item',
template: `
<li>
<ng-container *ngTemplateOutlet="itemTemplate; itemContext"></ng-container>
</li>
`,
})
export class ListItemComponent {
@Input()
public data: any;
@Input()
public itemTemplate: Template;
public get itemContext(): any {
return { $implicit: data };
}
}
You can then use it in different ways. I made an example just a simple list and another where the item template is again a list so you get a list of lists simmilar to a tree. Sample code:
@Component({
selector: 'my-app',
template: `
<list [items]="Items">
<ng-template let-items>{{ items | json }}</ng-template>
</list>
<list [items]="Items">
<ng-template let-items>
<list [items]="items">
<ng-template let-items>{{ items | json }}</ng-template>
</list>
</ng-template>
</list>
`,
})
export class App {
Items: Array<Array<string>> = [
[ "1-1", "1-2", "1-3", ],
[ "2-1", "2-2", "2-3", ],
[ "3-1", "3-2", "3-3", ],
[ "4-1", "4-2", "4-3", ],
[ "5-1", "5-2", "5-3", ],
]
}
I made also a plunker sample with the code where you can run it. Plunker Sample