update Material Table with data loaded in a parent component with ajax post

1.4k Views Asked by At

I'm currently having a problem with Angular with displaying data in a mat-table (table material) but after loading the data into an rxjs service (so asynchronously). The problem is that the data is not displayed. I tried to surender with a setTimeout the line this.dataSource = new MatTableDataSource, but that doesn't display the table either. I also tried adding an ngOnChange function that updates the table only when the table attribute is changed, and the data is displayed but I get an ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked...

For the components architecture, I have a table component with an input to inject data into the table.component.ts file from another component:

table.component.ts :

 @Component({
      selector: 'app-table',
      templateUrl: './table.component.html',
      styleUrls: ['./table.component.scss']
    })
    export class TableComponent implements OnChanges, OnInit {
    
       @Input() table: Table<any, any>;
    
       @ViewChild(MatPaginator) paginator: MatPaginator;
          
         ngOnInit(): void {
            this.table.columnDef.forEach(element => {
              if (element.columnDisplay) {
                this.displayedColumns.push(element.columnKey);
            }
          this.dataSource = new MatTableDataSource<PeriodicElement>(this.table.columnDataSource);
          this.dataSource.paginator = this.paginator;
         });
      }

The link with the MatTable object is made through the input variable "table" as following in html.

table.component.html :

 <table mat-table matTableExporter [dataSource]="this.dataSource"  >
  <div *ngFor="let col of table.columnDef">
    <ng-container *ngIf="col.columnDisplay" [matColumnDef]="col.columnKey">

      <th mat-header-cell *matHeaderCellDef>
        <img *ngIf="col.columnIcon.display" src="{{col.columnIcon.iconName}}" alt="image commune">
        {{col.columnValue}}
      </th>

      <div [ngSwitch]="col.columnKey">
        <td mat-cell *matCellDef="let element">
          <div *ngSwitchCase="'example'">{{element[col.columnKey].exampleAttribute}}</div>
          <div *ngSwitchDefault> {{element[col.columnKey]}} </div>
        </td>
      </div>

    </ng-container>
  </div>
</table>

<mat-paginator *ngIf="this.option.pagenation?.display" #paginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons
  aria-label="Select page of periodic elements">
</mat-paginator>

Then, there is the parent component (user in this case for the example) which calls the previous seen Table component. This other "user" component will load data into an Angular service and then inject it into the table with a subscribe in this way:

users.component.ts :

export class UsersComponent implements OnInit {

  users:User[]=[];
  USER_DATA: User[] = [];
  public userTable : Table<Column, User> ;

  constructor(private userService : UserService) { }
   
  userColumns: Column[] = [
    { columnKey: "username", columnValue: "Identifant" },
    { columnKey: "firstname", columnValue: "Prenom" },
    { columnKey: "lastname", columnValue: "Nom"},
  ]

  ngOnInit(): void {
    this.userService.getAllUsers().subscribe(response=>{
      this.USER_DATA = response;
      this.userTable = { columnDef: this.userColumns, columnDataSource: this.USER_DATA };
    });
    this.userTable = { columnDef: this.userColumns, columnDataSource: this.USER_DATA };
  }

} 

Finally in the user.component.html the injection is done like this:

user.component.html :

<div class="table">
     <app-table [table]="userTable"></app-table> 
</div>

I have tried some tests but nothing works as it should. Could you help me to find the right practices to handle my problem which is "How to update a component a Material Table from a parent component injecting data that it loads via an rxjs service?".

Thanks to you!

0

There are 0 best solutions below