[英]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.