I'm using angular-material to create a generic table. When I navigate to the details of an object in the table and when I want to open the table page from the menu, it does not render the data until I get some action with the paginator. I think that it is for the paginator, but, I don't have a solution.
Here is the class in typescript
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { PageEvent } from '@angular/material/paginator';
@Component({
selector: 'pc-tabla-paginada',
templateUrl: './tabla-paginada.component.html',
styles: `
#tableDiv { overflow-x: scroll; }
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TablaPaginadaComponent {
@Input()
public listaObjetos: any[] = [];
@Input()
public columnasAMostrar: string[] = [];
@Input()
public nombreColumnas : any = {};
@Input()
public encabezadoTabla: string = '';
@Input()
public pageSizeOptions: number[] = [5, 10, 20];
@Input()
public pageSize: number = 5;
@Input()
public length: number = 0;
@Output()
public page: EventEmitter<PageEvent> = new EventEmitter();
@Output()
public objeto: EventEmitter<any> = new EventEmitter();
public emitPaginationData(event: PageEvent) {
this.page.emit(event);
}
public enviarObjeto(elemento: any) {
this.objeto.emit(elemento);
}
public esFecha( value: any ): boolean {
if ( value === '' || value === null || value === undefined) return false;
const datoProbar = new Date(value);
if ( typeof value === 'object' && datoProbar.toString() !== 'Invalid Date') {
return true;
}
return false;
}
}
Here is the HTML
<div class="row col-12">
<div class="row col-12">
<h2>{{ encabezadoTabla }}</h2>
<hr>
</div>
<div class="mat-elevation-z8">
<div class="mat-elevation-z8 row" id="tableDiv">
<table mat-table [dataSource]="listaObjetos">
@for (columna of columnasAMostrar; track $index) {
<ng-container [matColumnDef] = columna >
<th mat-header-cell *matHeaderCellDef> {{ nombreColumnas[columna] }} </th>
<td mat-cell *matCellDef="let elemento">
@if ( columna === 'enableEdition') {
<button mat-raised-button
(click)="enviarObjeto(elemento)">
<mat-icon>more_horiz</mat-icon>
Más
</button>
} @else {
@if ( esFecha(elemento[columna]) ) {
{{elemento[columna] | date:'medium': '':'es-ES' }}
} @else {
{{elemento[columna]}}
}
}
</td>
</ng-container>
}
<tr mat-header-row *matHeaderRowDef="columnasAMostrar"></tr>
<tr mat-row *matRowDef="let row; columns: columnasAMostrar;"></tr>
</table>
</div>
<div class="row">
<mat-paginator
[pageSizeOptions] = "pageSizeOptions"
[length] = "length"
[pageSize] = "pageSize"
showFirstLastButtons
aria-label="Lista de Pedidos"
(page)="emitPaginationData($event)">
</mat-paginator>
</div>
</div>
</div>
As it is a generic component, I will call it like this
<pc-tabla-paginada
[listaObjetos]="listaObjetos"
[columnasAMostrar]="columnasAMostrar"
[nombreColumnas]="nombreColumnas"
[pageSizeOptions]="pageSizeOptions"
[pageSize]="pageSize"
[length]="length"
[encabezadoTabla]="encabezadoTabla"
(page)="getPaginationData($event)"
></pc-tabla-paginada>
So, in the constructor of the object, I'm not subscribing to any petition because it's generic. I have looked for a lot of solutions, but none of them fit my problem.
The issue you're experiencing, where the data doesn't render until you interact with the paginator, is likely related to change detection in Angular. Let's go through some potential solutions:
import { ChangeDetectorRef } from '@angular/core';
export class TablaPaginadaComponent {
constructor(private cdr: ChangeDetectorRef) {}
@Input() set listaObjetos(value: any[]) {
this._listaObjetos = value;
this.cdr.detectChanges();
}
get listaObjetos(): any[] {
return this._listaObjetos;
}
private _listaObjetos: any[] = [];
}
import { OnChanges, SimpleChanges } from '@angular/core';
export class TablaPaginadaComponent implements OnChanges {
ngOnChanges(changes: SimpleChanges) {
if (changes['listaObjetos']) {
// Perform any necessary updates
this.cdr.detectChanges();
}
}
}
<table mat-table [dataSource]="listaObjetos | async">
<!-- ... -->
</table>
import { ChangeDetectorRef } from '@angular/core';
export class ParentComponent {
constructor(private cdr: ChangeDetectorRef) {}
updateData() {
// Update your data
this.listaObjetos = [...]; // Create a new reference
this.cdr.detectChanges();
}
}
export class TablaPaginadaComponent {
trackByFn(index: number, item: any): any {
return item.id; // Use a unique identifier from your data
}
}
And in your template:
<table mat-table [dataSource]="listaObjetos" [trackBy]="trackByFn">
<!-- ... -->
</table>
export class ParentComponent implements OnInit {
listaObjetos: any[] = [];
ngOnInit() {
this.loadData();
}
loadData() {
// Your data loading logic here
this.someService.getData().subscribe(data => {
this.listaObjetos = data;
this.cdr.detectChanges();
});
}
}
<pc-tabla-paginada
*ngIf="listaObjetos.length > 0"
[listaObjetos]="listaObjetos"
...
></pc-tabla-paginada>
Try implementing these solutions one at a time, starting with forcing change detection (#1) as it's likely to be the most straightforward fix.