Dizzy
Dizzy

Reputation: 902

Angular 2 Template as a parameter to component

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

Answers (4)

RVandersteen
RVandersteen

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

IgorL
IgorL

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

Picci
Picci

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

Ankit Singh
Ankit Singh

Reputation: 24945

PLUNKER

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

Related Questions