0
votes

I'm working in an Angular2 v8 app, specificaly in a material explosion software. The problem is that when I want to calculate the cost of a product, all materials are separated in N groups, that's what I need N mat-table.

This is my array of groups:

groups: GroupItem[] = [
  { _id: '', name: 'Group 1', subtotal: 0, gain: 0, gainPercent: 0, total: 0, materials: [] },
  { _id: '', name: 'Group 2', subtotal: 0, gain: 0, gainPercent: 0, total: 0, materials: [] },
  { _id: '', name: 'Group 3', subtotal: 0, gain: 0, gainPercent: 0, total: 0, materials: [] }
];

If you see, each item of my groups has a property called materials and that's where I push my materials typed by my ProductMaterialItem interface.

export interface ProductMaterialItem {
  material: name;
  quantity: number;
  cost: number;
}

So, obviously, my many mat-table items has to display the data of each materials: [] array

This is my component.html where I want to print my materials

<div id="groups-container" style="width: 100%;">
    <div class="group-item" *ngFor="let group of groups; let i = index">
        <div id="group-header" class="group-header">
            <span>{{ group.name }}</span>
        </div>
        <div id="materials-content">
            <table mat-table [dataSource]="group.materials" fxFlex="100">
                <ng-container [matColumnDef]="column.name" *ngFor="let column of displayedColumnsA">
                    <th mat-header-cell *matHeaderCellDef> {{column.label}} </th>
                    <td mat-cell *matCellDef="let element"> {{element[column.name]}} </td>
                </ng-container>

                <ng-container matColumnDef="options">
                    <th mat-header-cell *matHeaderCellDef style="width: 30px;">
                      <a (click)="addMaterial(i)">Add Material</a>
                    </th>
                    <td mat-cell *matCellDef="let element" style="width: 30px;">
                        <mat-icon class="material-icons-outlined">cancel</mat-icon>
                    </td>
                </ng-container>

                <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
                <tr mat-row *matRowDef="let row; columns: columnsToDisplay;"></tr>
            </table>
        </div>
    </div>
</div>

this is my component.ts

displayedColumnsA = [
  { name: 'name', label: 'Material' },
  { name: 'quantity', label: 'Quantity' },
  { name: 'costu', label: 'Cost' },
  { name: 'costt', label: 'Total Cost' }];
displayedColumns: string[] = ['name', 'quantity', 'costu', 'costt', 'options'];
columnsToDisplay: string[] = this.displayedColumns.slice();

constructor() { }

ngOnInit() {}

addMaterial(index: number) {
this.dialogRef = this.dialog.open(AddMaterialComponent, {
  width: '650px',
  disableClose: true,
  data: { title: 'Add Material' }
});

this.dialogRef.afterClosed().subscribe(result => {
  if (result !== undefined) {
    if (result !== false) {
      this.groups[index].materials.push(result); // Everything works fine at this point, the material was added succsesfuly
      // and here is where I need to refresh the table whith the this.groups[index].materials new value. But I tried everything without succesful

      console.log(this.groups[index].materials);
    }
  }
});
}

Is any way to force the mat-table refresh with the new values?

Note: I tried ChangeDetectorRef and didn't work

2
This has been answered already here use renderRows() on tableSameer
Thank you @SameerKhan the solution worked, unfortunately it worked just for the first table, but the second, third, fourth or N, the problem still existsSergio Mendez
Added answer have a look :)Sameer

2 Answers

0
votes

I have found a solution for this problem, basically if you do:

this.dataSource.data.push(newElement); //Doesn't work

But if you replace the complete array then it works fine. So your final code must be :

this.socket.on('newMessage', function(event) {
const data = this.dataSource.data;
data.push(event);
this.dataSource.data = data;

});

You can see the issue here -> https://github.com/angular/material2/issues/8381

0
votes

Material table refresh for multiple tables

As explained here, you can get reference of mat-table using @ViewChild.

@ViewChild is to get first or single reference, to get multiple references you need to use @ViewChildren Example shown below

import {Component, ViewChildren} from '@angular/core';
...
@ViewChildren(MatTable) matTables : QueryList<MatTable>;
...

refreshFunc() {
 console.log(this.matTables); // this will log all the material table's references
 //You can also make use of toArray() function and loop, to get each reference
 this.matTables.toArray().forEach(each => each.renderRows());
}