Search code examples
angularangular-materialcalculated-columnscalculationmat-table

angular material mat-table: how to multiply two column values in a 3rd column


I have an angular material table with a dropdown column by which users can select the time length. After users provide the number of time, I wanted to calculate the service fee for each service type and then do a total to sum a total for all selected services. [1]: https://i.sstatic.net/m2ukB.jpg

The issue is the sub total (price * months) for all rows dynamically changes based on the last selected number of month although the previously selected months remain no change. This is my template

......
<ng-container matColumnDef="price">
    <mat-header-cell *matHeaderCellDef mat-sort-header> Price (USD/m) </mat-header-cell>
    <mat-cell *matCellDef="let element"> {{element.price | currency}} </mat-cell>
</ng-container>                                        
<ng-container matColumnDef="month">
    <mat-header-cell *matHeaderCellDef> Months </mat-header-cell>
    <mat-cell *matCellDef="let element">
            <mat-select placeholder="0" (selectionChange)="onChangeMonth($event)">
                <mat-option *ngFor="let month of months" [value]="month.value">
                {{ month.viewValue }}
                </mat-option>
            </mat-select> 
    </mat-cell>                     
</ng-container>
<ng-container matColumnDef="subtotal">
    <mat-header-cell *matHeaderCellDef> SubTotal </mat-header-cell>
    <mat-cell *matCellDef="let element">
        {{element.price * serviceLength}}
    </mat-cell>                               
</ng-container> 

......

And this is my ts:

export class StockAddsubsComponent implements OnInit {
  columnsToDisplay: string[] = ['id','name','price','month','subtotal'];
  listData: MatTableDataSource<any>;  
  months: any [] = [{value: 1, viewValue: 1}, {value: 3, viewValue: 3}, {value: 6, viewValue: 6}, {value: 12, viewValue: 12}
  ]; 
  serviceLength: number;
  
  @ViewChild(MatSort) sort: MatSort;
  
  constructor(private feesService: FeesService) { }

  ngOnInit(): void {
    this.createFeeList();
  }

  createFeeList() {                
    this.feesService.getFeeList().subscribe((data: []) => {
      this.listData = new MatTableDataSource(data);
      }, error => {
        console.log(error);
    });
  } 

  onChangeMonth(event) {
    this.serviceLength = event.value;
  }
}


Solution

  • just use [(ngModel)]="element.month" in your mat-select

    <mat-select placeholder="0" [(ngModel)]="element.month">
        <mat-option *ngFor="let month of months" [value]="month.value">
        {{ month.viewValue }}
        </mat-option>
    </mat-select>
    

    And use {{element.price*element.month}}

    NOTE: You can also use a getter to get the total and put in the footer of the table

    get total()
    {
        return this.listData.data.map(x=>x.month*x.price).reduce((a,b)=>a+b)
    }
    

    See stackblitz