I'm trying to create a general purpose container component for all tables so they all have same headers (possible buttons, filter-chips, search-field). I'm planning to use content projection with ng-content and passing data to the table using ContentChild. But this scenario works ONLY if the ContentChild is given the exact class of the component and not the base class. So I can't make it a general purpose container component that can be given any table component that extends the base class.
So I have
component-one.html
<app-table-container [data]="tableData">
<app-some-table></app-some-table>
</app-table-container>
table-container.component.html
<!-- here above the content projected table would be common
stuff for all tables -->
<ng-content select="[tableComponent]"></ng-content>
table-container.component.ts
@Component({
selector: 'app-table-container',
templateUrl: './table-container.component.html',
styleUrls: ['./table-container.component.scss']
})
export class TableContainerComponent implements AfterContentInit {
@Input() data: ITableStuff;
@ContentChild(TableBaseComponent) tableComponent: TableBaseComponent;
ngAfterContentInit(): void {
// below fails because this.tableComponent is undefined
this.tableComponent.data = this.data;
}
}
table-base.component.ts
@Component({
template: ''
})
export class TableBaseComponent implements AfterViewInit {
@Input() data: ITableStuff;
ngAfterViewInit(): void {
console.log(this.data.name);
}
}
some-table.ts
@Component({
selector: 'app-some-table',
template: '<p>some-table works!</p>'
})
export class SomeTableComponent extends TableBaseComponent implements {
constructor() {
super();
}
}
However in TableContainerComponent.ngAfterContentInit the this.tableComponent is undefined. If I have:
@ContentChild(SomeTableComponent) tableComponent: SomeTableComponent;
it works. But then there's nothing general purpose in my container component.
You have to create interface
ISomeInterfaceandInjectionToken<ISomeInterface>:Make each table-like component implement interface and provide itself as
InjectionToken<ISomeInterface>:and then use it in
ContentChild(mytoken):Instead of token you can use custom base class.