Im kinda beginner with Angular and just wondering if this is possible to achive.
list-people.component.html
<my-table [dataSource]="dataSource" [pagination]="true">
<my-column id="id" name="ID" sortable></my-column>
<my-column id="user" name="Full Name" *row="let row"> //Maybe somehow get the row data
{{ row.user.name }} {{ row.user.last }}
</my-column>
<my-column id="country" name="Country" sortable></my-column>
<my-column id="actions" name="">
<button (click)="edit(this)">Edit</button> //should get row data to edit click function
</my-column>
</my-table>
list-people.component.ts (Short ver)
export class ListPeople {
data: MatTableDataSource<?>;// ? Should be a interface
ngOnInit() {
const list = [
{
id: 1,
country: 'England',
user: {
name: 'Peter',
last: 'Gustavf'
}
}
];
this.data = new MatTableDataSource(list);
}
}
Ive tried but failed, so is this hard or should i give up on this? I did manage to print the values for each my-column inside my-table dont know what to do to continue
CodePudding user response:
Have your tried to check any of the examples on the Angular Material Table site
A basic example applied to your provided data could be like this
<table mat-table [dataSource]="data">
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef> ID. </th>
<td mat-cell *matCellDef="let element"> {{element.id}} </td>
</ng-container>
<ng-container matColumnDef="country">
<th mat-header-cell *matHeaderCellDef> Country </th>
<td mat-cell *matCellDef="let element"> {{element.country}} </td>
</ng-container>
<ng-container matColumnDef="user">
<th mat-header-cell *matHeaderCellDef> User </th>
<td mat-cell *matCellDef="let element"> {{element.user.name}} {{element.user.last}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
And in your ListPeople
component, add displayedColumns
property
displayedColumns: string[] = ['id', 'country', 'user'];
CodePudding user response:
Sure you can.
Imagine a .html to create a mat-data-table
<table *ngIf="displayedColumns" mat-table [dataSource]="dataSource">
<ng-container
*ngFor="let cell of cells; let i = index"
[matColumnDef]="displayedColumns[i]"
>
<th mat-header-cell *matHeaderCellDef>{{ titles[i]}}</th>
<td mat-cell *matCellDef="let element"></td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
You need datasource, displayedColumns, an Array titles and important the "TemplateRef" of the *matCellDef
So the idea is that in your .html you has some like
<app-my-table [source]="items">
<td app-cell name="name" title="Name" *row="let data">{{ data.name }}</td>
<td app-cell name="id" title="Id" *row="let data">{{ data.id }}</td>
</app-my-table>
See that you need two Directive, the directive "row" and the directive "app-cell"
@Directive({
selector: 'app-cell,td[app-cell]',
})
export class CellDirective {
@HostBinding('class')
@Input() name;
@Input() title;
constructor() {}
}
//and
@Directive({
selector: '[row]',
})
export class RowDirective {
constructor(public templateRef: TemplateRef<any>) {}
}
The app-table component like
export class AppTableComponent implements AfterViewInit {
@ContentChildren(CellDirective) cellDatas: QueryList<CellDirective>;
@ContentChildren(RowDirective) cells: QueryList<RowDirective>;
@ViewChildren(MatCellDef) cellDefs:QueryList<MatCellDef>
@ViewChild(MatTable) matTable:MatTable<any>
@Input() source
dataSource:any[];
displayedColumns:string[];
templates:TemplateRef<any>[]
titles: any[] = [];
constructor(private cdr: ChangeDetectorRef) {}
ngAfterViewInit() {
//first we give value to displayedColumns
setTimeout(()=>{
this.displayedColumns=this.cells.map((x,i)=>'col' i)
})
//we subscribe to cellDefs to asign the TemplateRef
//from our *row templates
this.cellDefs.changes.pipe(take(1)).subscribe(res=>{
const templates=this.cells.toArray().map(x=>x.templateRef);
res.forEach((x,i)=>{
x.template=templates[i]
})
setTimeout(()=>{
this.dataSource=this.source
})
})
//we get the "titles"
this.cellDatas.changes.pipe(take(1)).subscribe((res) => {
setTimeout(()=>{
this.titles = res
.map((x) => x.title)
.reduce((a, b) => (a.indexOf(b) < 0 ? [...a, b] : a), []);
})
});
}
}
NOTE: ther're a severals setTimeouts to avoid the error "afterchecked", if I'll get avoid, I 'll update the answer
The stackblitz