Reputation: 902
My simplified goal is to build a component which is a list with item template. E.g.:
<list>item</list>
Here is my code:
import {bootstrap} from 'angular2/platform/browser';
import {Component} from 'angular2/core';
@Component({
selector: 'list',
template: `
<ul>
<li *ngFor="let i of items" >
<ng-content></ng-content>
</li>
</ul>
`
})
class List {
items = [1, 2, 3];
}
@Component({
selector: 'app',
directives: [List],
template: '<list>item</list>'
})
class App { }
bootstrap(App, []);
Expected result:
Actual result:
•
•
• item
Upvotes: 37
Views: 26078
Reputation: 2137
This is how I did it:
Usage:
<ng-template #myTemplate let-item="item">
<strong>Name: </strong> {{item.name}}<br>
<strong>Id: </strong> {{item.id}}
</ng-template>
<app-template-param [items]="items" [template]="myTemplate"></app-template-param>
Component:
@Component({
selector: 'app-template-param',
templateUrl: 'template-param.html'
})
export class TemplateParamComponent implements OnInit {
@Input() items: Array<any>;
@Input() template: TemplateRef<any>;
}
Component HTML
<ng-template #defaultTemplate let-item="item">
<strong>{{item.name}}</strong>
</ng-template>
<ul>
<li *ngFor="let item of items">
<ng-template [ngTemplateOutlet]="template || defaultTemplate" [ngTemplateOutletContext]="{item: item}"></ng-template>
</li>
</ul>
Upvotes: 51
Reputation: 1169
I found 3 ways to do it
@Component({
selector: 'dynamic-list',
template: '<div *ngFor="#item of items" *ngForTemplate="itemTemplate"></div>'
})
export class DynamicListComponent {
@ContentChild(TemplateRef)
public itemTemplate: TemplateRef;
@Input()
public items: number[];
}
<dynamic-list [items]="items">
<div template="#item">
Inline template item #: {{item}}
</div>
</dynamic-list>
output:
Inline template item #: 1
Inline template item #: 2
Inline template item #: 3
Inline template item #: 4
plunker: https://plnkr.co/edit/ollxzUhka77wIXrJGA9t?p=preview
see more https://github.com/ilio/ng2-dynamic-components/blob/master/README.md
Upvotes: 15
Reputation: 17752
I would consider changing slightly the design. Instead of inserting content between <list>
and </list>
and reference such content via ng-content
in the List
component, I would create a Component that plays the role of content (i.e. "repeat template with local variables passed, so each item is different") with the required input variables and insert the Component into the list. In other words something like this
ContentComponent
@Component({
selector: 'my-content',
inputs: ['inputVar'],
template: `<div>Item no. {{inputVar}}</div>`
})
export class MyContent {
inputVar: string;
}
List
@Component({
selector: 'list',
directives: [MyContent],
template: `
<ul>
<li *ngFor="let i of items" >
<my-content [inputVar]="i"></my-content>
</li>
</ul>
`
})
class List {
items = [1, 2, 3];
}
I hope it helps
Upvotes: 0
Reputation: 24945
AFAI tried <ng-content>
can't be binded repeatedly, but you can pass item
as input, like this
import {Component} from 'angular2/core';
@Component({
selector: 'list',
inputs: ['htmlIN'],
template: `
<ul>
<li *ngFor="#i of items" >
{{i}} {{htmlIN}}
</li>
</ul>
`
})
export class List {
htmlIN: any;
items = [1, 2, 3, 4];
}
@Component({
selector: 'my-app',
directives: [List],
template: `<list htmlIN="item"></list>`
})
export class App {
constructor(){
}
}
Upvotes: 2