假设我有这个简单的列表渲染组件:
- import {Input,Component } from 'angular2/core'
- @Component({
- selector: 'my-list',template: `
- <div *ngFor='#item of items' (click)='onItemClicked(item)'>
- {{item}}
- </div>
- `
- })
- class MyList {
- @Input() items: string[];
- onItemClicked(item) { console.log('Item clicked:',item); }
- }
我这样用:
- <my-list [items]='myAppsItems'></my-list>
到现在为止还挺好.
接下来,我决定我希望用户能够为渲染的项目提供自己的模板,因此我更改了组件
- @Component({
- selector: 'my-list',template: `
- <template ngFor [ngForOf]="items" [ngForTemplate]="userItemTemplate" (click)='onItemClicked(item)'>
- </template>
- `
- })
- class MyList {
- @Input() items: string[];
- @ContentChild(TemplateRef) userItemTemplate: TemplateRef;
- onItemClicked(item) { console.log('Item clicked:',item); }
- }
并使用它:
- <my-list [items]='items'>
- <template #item>
- <h1>item: {{item}}</h1>
- </template>
- </my-list>
这只有我不绑定任何事件处理程序到列表项(plunker).如果我尝试绑定到点击事件,就像我在组件的第一个版本中一样,Angular会抛出以下异常:
- "Event binding click not emitted by any directive on an embedded template"
这是一个plunker showing that.您可以删除点击绑定,它将工作.
我该如何解决?我只想让用户能够指定一个下级项目的模板,我将通过ngFor进行迭代,但是我需要能够将处理程序绑定到这些项目.
项目模板在应用程序上下文中定义,但不清楚如何将其附加到我的列表组件上下文中.我有创建包装指令来处理模板及其变量,指令被包装到div中以捕获事件.它可以像这样使用:
- @Directive({
- selector: '[ngWrapper]'
- })
- export class NgWrapper
- {
- @Input()
- private item:any;
- private _viewContainer:ViewContainerRef;
- constructor(_viewContainer:ViewContainerRef)
- {
- this._viewContainer = _viewContainer;
- }
- @Input()
- public set ngWrapper(templateRef:TemplateRef)
- {
- var embeddedViewRef = this._viewContainer.createEmbeddedView(templateRef);
- embeddedViewRef.setLocal('item',this.item)
- }
- }
- @Component({
- selector: 'my-list',directives: [NgWrapper],template: `
- <template ngFor #item [ngForOf]="items">
- <div (click)="onItemClicked(item)">
- <template [ngWrapper]="userItemTemplate" [item]="item"></template>
- </div>
- </template>
- `
- })
- class MyList {
- @Input() items: string[];
- @ContentChild(TemplateRef) userItemTemplate: TemplateRef;
- userItemTemplate1: TemplateRef;
- onItemClicked(item) {
- console.log('Item click:',item);
- }
- ngAfterViewInit(){
- this.userItemTemplate;
- }
- }
- @Component({
- selector: 'my-app',directives: [MyList],template: `
- <my-list [items]='items'>
- <template #item="item">
- <h1>item: {{item}}</h1>
- </template>
- </my-list>
- `
- })
- export class App {
- items = ['this','is','a','test']
- onItemClicked(item) {
- console.log('Item click:',item);
- }
- }