I'm trying to write a simple list view (grid view?) with multiple columns using Angular 2 that I can instantiate this way:
<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>
I actually managed to make this work in a very hacky way, it generates a table with the information data I set in the FileListColumn component.
This is what I have at the moment:
FileListColumn component, where the column metadata is defined:
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 component, this is the main component for the list view:
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];
}
}
This this is the view for the FileList
component:
<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>
The hacky thing I mentioned is that, the way it works, for each column of each item, the only thing it does is that it calls the getProperty function passing the item and the field name and returns the value of that field, which is a less than ideal solution.
What I want to be able to do now is to be to set content in my columns the way shown below and have that content shown in my table:
<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>
Not only that, but I also want to be able to define the html for the column in the FileListColumn
component itself in order to keep the code a bit more organized.
One of the things I tried was to add a template in the view of the FileListColumn
component:
<template #columnTemplate>
<span>text to see if worked</span>
<ng-content></ng-content>
</template>
Then I tried to get its reference in the FileListColumn
component with:
@ViewChild('columnTemplate') columnTemplate: TemplateRef<any>;
And then I tried to load it in the view of the FileList
component by using:
<td *ngFor="let col of columns" *ngForTemplate="col.columnTemplate">
</td>
But I get an error on the browser saying:
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
Even if this worked, I wouldn't have any idea on how to actually bind the item in my items array to the FileListColumn
content.
Does anyone have an idea on how I can achieve those things?
I have been looking into a way solve this problem all day but I couldn't find anything useful, most tutorials are irrelevant as they were written for old betas of Angular 2 using older APIs.
Thanks in advance for the help and sorry for the long post.
Update 1:
So, I managed to load the template from FileListColumn
inside of the <td>
in the FileList
using the #columnTemplate attempt by doing this based on one of Günter Zöchbauer's links:
<tr *ngFor="let item of items">
<td *ngFor="let col of columns">
<template [ngTemplateOutlet]="col.columnTemplate" [ngOutletContext]="item"></template>
</td>
</tr>
The template is loaded inside every single cel but there are still two problems:
- The only properties I can access from the template are the column properties, I have no access to the item properties from the outer
ngFor
. - When I add content to the
FileListColumn
by doing<file-list-column><div>Content here</div></file-list-column>
to be loaded in the<ng-content>
of the column's template, this content is only showed in the last row, meaning it's not repeated in all rows.