Hello I am currently building a table that will allow multiple column types in it. I want to be able to use this like:
<my-table [rows]="rows">
<text-column [someParameters]="here" header="text"></text-column>
<icon-column [someParameters]="here" header="icon"></icon-column>
</my-table>
text-column
and icon-column
are separate directives.
I currently have an abstract class called column
and lets say the text-column
and the icon-column
may look something like:
export abstract class Column
{
@Input() someParameters:string;
@Input() header:string;
}
export class TextColumnDirective extends Column
{
//I do cool stuff here
}
export class IconColumnDirective extends Column
{
//I do different cool stuff
}
My table may look something like:
@Component({
selector:'my-table',
template: `
<table>
<thead>
<tr>
<th *ngFor="let column of columns">{{column.header}}</th>
</tr>
</thead>
</table>
`
})
export class MyTableComponent
{
@ContentChildren(Column) columns:QueryList<any>;
//I do cool stuff too
}
So this approach works if I do not use an abstract and just call it with just text column like @ContentChildren(TextColumnDirective) columns:QueryList<any>;
but only gets the text column and the same with the icon column. How can I accomplish this where I can add different types of directives for different columnTypes later?
The answer from @3xGuy is correct but the forwardRef(() => {})
is not required unless the type being provided is defined after the decorator or the decorated class see this Angular In Depth post
Note this approach can be used for ContentChildren
or ViewChildren
, below I use ViewChildren
item.ts
import { Directive } from '@angular/core';
export class Item {
color = '';
}
@Directive({
selector: '[blueItem]',
providers: [{ provide: Item, useExisting: BlueItemDirective }],
})
export class BlueItemDirective { // 'extends Item' is optional
color = 'blue';
}
@Directive({
selector: '[redItem]',
providers: [{ provide: Item, useExisting: RedItemDirective }],
})
export class RedItemDirective { // 'extends Item' is optional
color = 'red';
}
app.component.ts
import { Component, ViewChildren, QueryList } from '@angular/core';
import { Item } from './item';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Multiple View Child Types';
// Note we query for 'Item' here and not `RedItemDirective'
// or 'BlueItemDirective' but this query selects both types
@ViewChildren(Item) viewItems: QueryList<Item>;
itemColors: string[] = [];
ngAfterViewInit() {
this.itemColors = this.viewItems.map(item => item.color);
}
}
app.component.html
<div redItem>Item</div>
<div blueItem>Item</div>
<div blueItem>Item</div>
<div blueItem>Item</div>
<div redItem>Item</div>
<h2>Colors of the above directives</h2>
<ul>
<li *ngFor="let color of itemColors">{{color}}</li>
</ul>
Here is a StackBlitz showing this behavior in action.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With