Reputation: 1
I have an Angular 17 application, where I have a folder called components and within it I will create the components to be reusable, I created an initial one using mat-table.
The problem is that I have a column called action, which is dynamic, that is, it may or may not exist, so far everything is working, I can show and hide this column, the problem is that the buttons that should appear in this column when active are not being shown.
Below is the html of the parent component
<mat-card>
<mat-card-header>
<mat-card-title>Listagem de doadores</mat-card-title>
</mat-card-header>
<mat-card-content>
@if (value$ | async; as valor) {
<aldenora-tabela [dataSources]="valor" [displayedColumns]="displayedColumns" [hasActionColumn]="true" [actionButtons]="actionButtons" (buttonClick)="handleButtonClick($event)">
></aldenora-tabela>
}@else {
<p>Não foram encontrados registros...</p>
}
</mat-card-content>
</mat-card>
The component that passes the data to the table to be rendered is <aldenora-tablea>
This is the .ts of the parent component.
export class DoadoresComponent implements OnInit {
service: DoadoresService = inject(DoadoresService);
value$: Observable<Doadores[]> | null = null;
displayedColumns = ['Doador', 'Documento', 'Idade', 'Tipo'];
actionButtons = [
{ label: 'Edit', icon: 'edit' },
{ label: 'Delete', icon: 'delete' }
];
ngOnInit(): void {
this.value$ = this.service.getAllDoador({pagina:1, limite:3});
}
handleButtonClick(event: any) {
// Handle button click here
console.log('Button clicked:', event.button.label, 'for element:', event.element);
}
}
Below the .html component of the table
<div class="example-table-container">
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" matSort matSortActive="created" matSortDisableClear matSortDirection="desc">
<!-- Column -->
@for ( column of displayedColumns; track column) {
<ng-container [matColumnDef]="column">
<th mat-header-cell *matHeaderCellDef>{{ column }}</th>
<td mat-cell *matCellDef="let element">{{element[column] }}</td>
</ng-container>
}
<!-- Action Column -->
@if (hasActionColumn) {
<ng-container matColumnDef="actions" stickyEnd>
<th mat-header-cell *matHeaderCellDef> Actions </th>
<td mat-cell *matCellDef="let element">
@for ( button of actionButtons; track button) {
<button mat-icon-button (click)="onButtonClick(button, element)">
<mat-icon fontIcon="{{button.icon}}"></mat-icon>
{{button.label}}
</button>
}
</td>
</ng-container>
}
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
And finally the .ts component of the table
export class TabelaComponent implements OnInit {
//@Input() dataSources: Doadores[] = [];
@Input() displayedColumns: string[] = [];
@Input() hasActionColumn: boolean = false;
@Input() actionButtons: any[] = [];
dataSource = new MatTableDataSource<Doadores>([]);
@Input() set dataSources(data: any[]) {
this.setTableDataSource(data);
}
@Output() buttonClick: EventEmitter<any> = new EventEmitter<any>();
constructor() { }
ngOnInit(): void {
this.addColunaAction();
}
setTableDataSource(data: any) {
this.dataSource = new MatTableDataSource<Doadores>(data);
//this.tableDataSource.paginator = this.matPaginator;
//this.tableDataSource.sort = this.matSort;
}
// addColunaAction(){
// this.displayedColumns = this.displayedColumns.map(col => col);
// if (this.hasActionColumn) {
// this.displayedColumns.push('Action');
// }
// }
onButtonClick(button: any, element: any) {
this.buttonClick.emit({ button, element });
}
}
So, when this hasActionColumn variable had its value as true, the code below should be rendered and thus show the action column and the row buttons, which could be one button or more, but it didn't work.
<!-- Action Column -->
@if (hasActionColumn) {
<ng-container matColumnDef="actions" stickyEnd>
<th mat-header-cell *matHeaderCellDef> Actions </th>
<td mat-cell *matCellDef="let element">
@for ( button of actionButtons; track button) {
<button mat-icon-button (click)="onButtonClick(button, element)">
<mat-icon fontIcon="{{button.icon}}"></mat-icon>
{{button.label}}
</button>
}
</td>
</ng-container>
}
So I created a method in .ts to show this column and call it at the start of the component, this way every time the variable hasActionColumn is true the column appears, but the buttons do not.
ngOnInit(): void {
this.addColunaAction();
}
addColunaAction(){
this.displayedColumns = this.displayedColumns.map(col => col);
if (this.hasActionColumn) {
this.displayedColumns.push('Action');
}
}
Would anyone have any help?
Upvotes: 0
Views: 287
Reputation: 452
Your are using two columns: Action in component.ts and actions in HTML.
<ng-container matColumnDef="actions" stickyEnd>
this.displayedColumns.push('Action');
Don't use a different naming for matColumnDef :
Column definition for the mat-table. Defines a set of cells available for a table column.
You call the matColumns actions outside the loop and you can create a duplicate column with this approach.
<!-- Column -->
@for ( column of displayedColumns; track column) {
<ng-container [matColumnDef]="column">
<th mat-header-cell *matHeaderCellDef>{{ column }}</th>
<td mat-cell *matCellDef="let element">{{element[column] }}</td>
</ng-container>
}
<!-- Action Column -->
@if (hasActionColumn) {
<ng-container matColumnDef="actions" stickyEnd>
<th mat-header-cell *matHeaderCellDef> Actions </th>
<td mat-cell *matCellDef="let element">
@for ( button of actionButtons; track button) {
<button mat-icon-button (click)="onButtonClick(button, element)">
<mat-icon fontIcon="{{button.icon}}"></mat-icon>
{{button.label}}
</button>
}
</td>
</ng-container>
}
I would do that :
<!-- Column -->
@for (column of displayedColumns; track column) {
<!-- Action Column -->
@if (hasActionColumn && column === 'actions') {
<ng-container [matColumnDef]="column" stickyEnd>
<th mat-header-cell *matHeaderCellDef> Actions</th>
<td mat-cell *matCellDef="let element">
@for (button of actionButtons; track $index) {
<button mat-icon-button (click)="onButtonClick(button, element)">
<mat-icon fontIcon="{{button.icon}}"></mat-icon>
{{ button.label }}
</button>
}
</td>
</ng-container>
} @else {
<ng-container [matColumnDef]="column">
<th mat-header-cell *matHeaderCellDef>{{ column }}</th>
<td mat-cell *matCellDef="let element">{{ element[column] }}</td>
</ng-container>
}
}
Upvotes: 0