[英]Display component's content from @ContentChildren in multiple rows using *ngFor on Angular 2
我正在尝试使用Angular 2编写一个具有多个列的简单列表视图(网格视图?),我可以用这种方式实例化:
<file-list [items]="items">
<file-list-column title="Id" field="id"></file-list-column>
<file-list-column title="Name" field="name"></file-list-column>
</file-list>
实际上,我设法以一种非常笨拙的方式使其工作,它使用我在FileListColumn组件中设置的信息数据生成了一个表。
这是我目前所拥有的:
FileListColumn组件,其中定义了列元数据:
import {Component, Input, TemplateRef, ViewChild} from '@angular/core';
@Component({
selector: 'file-list-column',
template: ''
})
export class FileListColumn {
@Input()
public title: string;
@Input()
public field: string;
ngOnInit() {
}
}
FileList组件,这是列表视图的主要组件:
import {Component, Input, ContentChildren, QueryList, AfterContentInit, forwardRef} from '@angular/core';
import {FileListColumn} from './file.list.column';
import {IItem} from 'models';
@Component({
selector: 'file-list',
template: require('./file.list.html')
})
export class FileList implements AfterContentInit {
@ContentChildren(forwardRef(() => FileListColumn))
public columns: QueryList<FileListColumn>;
@Input()
public items: IItem[];
constructor() {
}
public ngAfterContentInit() {
}
public getProperty(item:{[key:string]:any}, name:string) {
return item[name];
}
}
这是FileList
组件的视图:
<table>
<thead>
<tr>
<th *ngFor="let col of columns">
{{col.title}}
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of items">
<td *ngFor="let col of columns">
{{getProperty(item, col.field)}}
</td>
</tr>
</tbody>
</table>
我提到的问题是,对于每个项目的每一列,它的工作方式都是,它调用getProperty函数,该函数传递项目和字段名称并返回该字段的值,即不太理想的解决方案。
我现在想做的就是以如下所示的方式在我的列中设置内容,并在我的表中显示该内容:
<file-list [items]="items">
<file-list-column title="Id" field="id"></file-list-column>
<file-list-column title="Name">
<span>{{$item.name}}</span>
</file-list-column>
<file-list-column title="Some other column">
<some-component item="$item"></some-component>
</file-list-column>
</file-list>
不仅如此,我还希望能够为FileListColumn
组件本身中的列定义html,以使代码更有条理。
我尝试做的一件事是在FileListColumn
组件的视图中添加一个模板:
<template #columnTemplate>
<span>text to see if worked</span>
<ng-content></ng-content>
</template>
然后,我尝试使用以下方法在FileListColumn
组件中获取其引用: @ViewChild('columnTemplate') columnTemplate: TemplateRef<any>;
然后,我尝试使用以下命令在FileList
组件的视图中加载它:
<td *ngFor="let col of columns" *ngForTemplate="col.columnTemplate">
</td>
但是我在浏览器上收到一条错误消息:
Error: Template parse errors:(…) "Error: Template parse errors:
Can't have multiple template bindings on one element. Use only one attribute named 'template' or prefixed with * ("
<tbody>
<tr *ngFor="let item of items">
<td *ngFor="let col of columns" [ERROR ->]*ngForTemplate="col.columnTemplate">
</td>
</tr>
"): FileList@10:44
即使这样做有效,我也对如何将我的items数组中的项目实际绑定到FileListColumn
内容FileListColumn
。
有人对我如何实现这些目标有想法吗?
我整天都在研究解决此问题的方法,但是我找不到任何有用的东西,大多数教程都是无关紧要的,因为它们是使用较旧的API为Angular 2的旧beta编写的。
在此先感谢您的帮助,对于冗长的帖子,我们深表歉意。
更新1:
所以,我设法加载从模板FileListColumn
内的<td>
中的FileList
利用这样的基础上冈特Zöchbauer的环节之一#columnTemplate尝试:
<tr *ngFor="let item of items">
<td *ngFor="let col of columns">
<template [ngTemplateOutlet]="col.columnTemplate" [ngOutletContext]="item"></template>
</td>
</tr>
模板加载到每个单元格中,但是仍然存在两个问题 :
ngFor
访问项目属性。 <file-list-column><div>Content here</div></file-list-column>
并将其添加到FileListColumn
的内容以加载到列模板的<ng-content>
中时,此内容仅在最后一行显示,这意味着不会在所有行中都重复显示。 因此,我根据GünterZöchbauer的答案中的链接找到了解决问题的方法。
在FileList
组件中,我添加了一个<template>
元素以从FileListColumn
组件中加载模板。 现在看起来像这样:
<tr *ngFor="let item of items">
<td *ngFor="let col of columns">
<template [ngTemplateOutlet]="col.columnTemplate" [ngOutletContext]="{ item: item, column: col }"></template>
</td>
</tr>
如您所见,我将该item
作为ngOutletContext
传递,这样我就可以在模板中对其进行访问。
现在,这是FileListColumn
的模板的样子:
<template #internalColumnTemplate let-item="item">
<span *ngIf="field">{{item[field]}}</span>
<template *ngIf="externalTemplate" [ngTemplateOutlet]="externalTemplate" [ngOutletContext]="{ item: item }"></template>
</template>
它具有可以在代码中引用的#internalColumnTemplate
选择器,以及具有let-item="item"
引用,该引用引用了我在ngOutletContext
传递的项目,并使其在模板内可用。 因此,基本上,如果设置了field
属性,则显示带有span
的字段值,否则,如果设置了externalTemplate
,这是我在FileListColumn
组件中设置的另一个属性,它将显示我在FileListColumn
定义中传递的任何模板。
这是完整的解决方案:
FileList组件file.list.ts :
import {Component, Input, ContentChildren, QueryList, AfterContentInit, forwardRef} from '@angular/core';
import {FileListColumn} from './file.list.column';
import {IItem} from 'models';
@Component({
selector: 'file-list',
template: require('./file.list.html')
})
export class FileList implements AfterContentInit {
@ContentChildren(forwardRef(() => FileListColumn))
public columns: QueryList<FileListColumn>;
@Input()
public items: IItem[];
constructor() {
}
public ngAfterContentInit() {
}
}
FileList模板file.list.html :
<table>
<thead>
<tr>
<th *ngFor="let col of columns">
{{col.title}}
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of items">
<td *ngFor="let col of columns">
<template [ngTemplateOutlet]="col.columnTemplate" [ngOutletContext]="{ item: item }"></template>
</td>
</tr>
</tbody>
</table>
FileListColumn组件file.list.component.ts :
import {Component, Input, TemplateRef, ViewChild, ContentChild} from '@angular/core';
@Component({
selector: 'file-list-column',
template: require('./file.list.column.html')
})
export class FileListColumn {
@Input()
public title: string;
@Input()
public field: string;
@ContentChild(TemplateRef)
public externalTemplate: TemplateRef<any>;
@ViewChild('internalColumnTemplate')
public columnTemplate: TemplateRef<any>;
ngOnInit() {
}
}
externalTemplate
属性是在使用FileList
组件时设置的可选模板,而columnTemplate
是FileListColumn
视图中的内部模板,如上和以下所示。
FileListColumn模板file.list.column.html :
<template #internalColumnTemplate let-item="item">
<span *ngIf="field">{{item[field]}}</span>
<template *ngIf="externalTemplate" [ngTemplateOutlet]="externalTemplate" [ngOutletContext]="{ item: item }"></template>
</template>
设置后,如何使用控件FileList组件:
<div>
<file-list [items]="fakeItems">
<file-list-column title="Id">
<template let-item="item">
<div>external {{item.id}}{{item.name}}</div>
</template>
</file-list-column>
<file-list-column title="Name" field="name"></file-list-column>
</file-list>
</div>
如您所见,您可以选择只传递要使用的字段,列将解决该问题,或者您可以为列设置<template>
并使用任何要使用的html,不要忘记如上所示添加let-item="item"
,以便您可以访问该项目。
基本上就是这样。 我希望这对其他人有用。
如果您有任何疑问或建议来改进它,请告诉我,我会进行更新。
顺便说一句,我正在使用Angular 2.0.1 。
您可以通过以下方式使用ngForTemplate
:
<template ngFor let-col [ngForOf]="colums" [ngForTemplate]="col?.columnTemplate">
<td></td>
</template>
我不知道这是否可以解决您所有的问题。
这可能也很好(我自己没有尝试过)
<td *ngFor="let col of columns template:col?.columnTemplate">
</td>
实际上,我尝试过:-/ 重复使用ng-content 。 也许某些改变改变了这种方法。
也可以看看
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.