Array in object with mat-Table in Angular

Issue

the table works almost well, the problem is that all the "solde" values ​​appear in the same column.

I want to display each balance and month value in a column, I tried to loop "mnth" but it doesn’t work

this table is dynamically
how to display each solde value in a different column ?

export class visionCompacteDTOs {
    collaborator!:string;
    cetCP!:number;
    cetRTT!:number;
    perteRTT!:number;
    perteCP!:number;
    mnth:Month[]=[];
}

export class Month {
  month!: Date;
  solde!: number;
}

db.json :

{
    "visionCompacteDTO": [
        {
            "collaborator": "Jean",
            "cetCP": 0,
            "cetRTT": 0,
            "perteRTT": 3.56,
            "perteCP": 4,
            "mnth": [
                {
                 "month": "July",
                 "solde": 14.52
                },
                {
                 "month": "August",
                 "solde": 15.52
                },
                {
                 "month": "September",
                 "solde": 16.52
                },
                {
                    "month": "October",
                    "solde": 18.52
                },
                {
                    "month": "November",
                    "solde": 19.52
                },
                {
                    "month": "December",
                    "solde": 20.52
                }
            ]
        }
    ]
}

file.ts:

export class CompacteComponent {
  don: any;
  sld:any;
  userdata:any=[];
  constructor(private reportingService:ReportingService) { }

  columns: string[] = ['collaborator', 'cetCP', 'cetRTT', 'moisSoldes', 'perteRTT', 'perteCP','mnth'];
  index: string[] = ['collaborator', 'cetCP', 'cetRTT', 'moisSoldes', 'perteRTT', 'perteCP','mnth'];

  dataSource :visionCompacteDTOs[] = [];
  
  ngOnInit():void {
    
    this.reportingService.getNews().subscribe((response)=>{
      this.dataSource = response;
      console.log(response)
      for (let i = 0; i < response.length; i++) {
        var username:any = this.dataSource[i].mnth;
        this.userdata = username;
        console.log(this.userdata);
        for (let j = 0; j < username.length; j++) {
          this.don = username[j].month;
          this.sld = this.userdata[j].solde;
          console.log(this.sld);
        }
      }
    },
    (error)=>{
      console.log("Error Occured: "+error);
    }
    )
  }

}

file.html :

<table mat-table [dataSource]="dataSource" class="mat-elevation-z8 lftm">
  <ng-container matColumnDef="collaborator">
    <th mat-header-cell *matHeaderCellDef> </th>
    <td mat-row *matCellDef="let element"> {{element.collaborator}} </td>
  </ng-container>
  
  <ng-container matColumnDef="cetCP">
    <th mat-header-cell *matHeaderCellDef > cetCP </th>
    <td mat-cell *matCellDef="let element"> {{element.cetCP}} </td>
  </ng-container>
  <ng-container matColumnDef="cetRTT">
    <th mat-header-cell *matHeaderCellDef > cetRTT </th>
    <td mat-cell *matCellDef="let element"> {{element.cetRTT}} </td>
  </ng-container>

   
  <ng-container  matColumnDef="mnth">
    <th mat-header-cell *matHeaderCellDef >
      <span *ngFor="let solde of this.userdata"> {{solde.month}} </span></th>
    <td mat-cell *matCellDef="let element" >
      <span *ngFor="let loc of this.userdata"> {{loc.solde}}</span>  </td>
  </ng-container>

  <ng-container matColumnDef="perteRTT">
    <th mat-header-cell *matHeaderCellDef class="prt"> Perte RTT </th>
    <td mat-cell *matCellDef="let element"> {{element.perteRTT}} </td>
  </ng-container>
  <ng-container matColumnDef="perteCP">
    <th mat-header-cell *matHeaderCellDef class="prt"> Perte CP </th>
    <td mat-cell *matCellDef="let element"> {{element.perteCP}} </td>
  </ng-container>
...
...

Solution

Concept (in short)

1.0 Retrieve first row’s mnth and add into displayedColumns and displayedMonthColumns arrays.

1.1 Add into displayedColumns for the columns must be existed and be required by mat-header-row and mat-row.

1.2 Add into displayedMonthColumns for generating columns via *ngFor.

2.1 Generate object (mnthObj) from mnth with month and solde as key value pair via reduce.

3.1 Create new array result with existing visionCompacteDTO object and mnthObj via map.


Solution

.component.html

<table mat-table [dataSource]="dataSource" class="mat-elevation-z8 lftm">
  ...

  <ng-container *ngFor="let month of displayMonthColumns">
    <ng-container matColumnDef="{{month}}">
      <th mat-header-cell *matHeaderCellDef> {{month}} </th>
      <td mat-cell *matCellDef="let element"> {{element[month]}} </td>
    </ng-container>
  </ng-container>
</table>

.component.ts

export class CompacteComponent implements OnInit {

  ...

  displayedColumns: string[] = [
    'collaborator',
    'cetCP',
    'cetRTT',
    'perteRTT',
    'perteCP'
  ];

  displayMonthColumns: string[] = [];

  ngOnInit(): void {
    this.reportingService.getNews().subscribe(
      (response: visionCompacteDTOs[]) => {
        if (!response) this.dataSource = response;

        for (let mnth of response[0].mnth) {
          this.displayedColumns.push(mnth.month);
          this.displayMonthColumns.push(mnth.month);
        }

        response = response.map(data => {
          let mnth = data.mnth;

          let mnthObj: { [key: string]: number } = mnth.reduce(function(
            obj: { [key: string]: number },
            item
          ) {
            obj[item.month] = item.solde;
            return obj;
          },
          {});

          return {
            ...data,
            ...mnthObj
          };
        });

        this.dataSource = response;
        console.log(response);
      },
      error => {
        console.log('Error Occured: ' + error);
      }
    );
  }
}

Sample Solution on StackBlitz

Result

Answered By – Yong Shun

Answer Checked By – Cary Denson (AngularFixing Admin)

Leave a Reply

Your email address will not be published.