0

I would like to do an angular 13 looping to split data to one column when duplicate entries came from database

now I got like this enter image description here

I Want like this

enter image description here

<table class="custom-table">
<thead>
<tr>
<td colspan="2">&nbsp;</td>
<th colspan="3" scope="colgroup" class="text-center">{{'JobAllowanceperMonth.JobAllowanceperMonth' |
translate}}</th>
 </tr>
  <tr>
<th scope="col">{{ 'Organization.Organization' |
translate}}</th>
<th scope="col">{{ 'AttendancebenifitperDay.AttendancebenifitperDay' |
 translate}}</th>
 <th scope="col">{{ 'Step01.Step01' |
 translate}}</th>
 <th scope="col">{{ 'Step02.Step02' |
  translate}}</th>
 <th scope="col">{{ 'Step03.Step03' |
translate}}</th>                    
  </tr>
 </thead>
    <tbody *ngFor="let salaryVUGDetails of VUGSalaryDetails">
       <tr>
      <th scope="col">{{salaryVUGDetails.OrganisationName}}</th>
        <td>00,000</td>
         <td>{{salaryVUGDetails.Step1}}</td>
          <td>{{salaryVUGDetails.Step2}}</td>
        <td>{{salaryVUGDetails.Step3}}</td>
    </tr>
     </tbody>
  </table>
Rishf P
  • 49
  • 5

2 Answers2

1

I see the demand for preprocessing your VUGSalaryDetails. I prefer to pipe over the Observables directy, but since your code seems to have the data stored in a variable directly, I work upon that in the controller. The following solution assumes, that each organization has exactly three steps:

// The final datastructure will be a hashmap pointing the organizationName as a key to an array of {step1,step2,step3} entries: 
public processedData: Map<string, {
    Step1: number,
    Step2: number,
    Step3: number
}[]> = new Map<string, {
    Step1: number,
    Step2: number,
    Step3: number
}[]>; 


let VUGSalaryDetails = [
    { 
        "OrganizationName": "Organization Level",
        "Step1": "4900",
        "Step2": "5400",
        "Step3": "5600" },
    { 
        "OrganizationName": "Organization Level",
        "Step1": "18826",
        "Step2": "18926",
        "Step3": "19026" },
    ...
]; // example data to work with.

// now we loop through the originalData and add them to the hashmap:
for (let i = 0; i < VUGSalaryDetails.length; i++) {
    // if the hashmap has no entry yet for the current organizationName, then set it:
    if (!this.processedData.has(VUGSalaryDetails[i].OrganizationName) {
        this.processedData.set(VUGSalaryDetails[i].OrganizationName, [{
            Step1: VUGSalaryDetails[i].Step1,
            Step2: VUGSalaryDetails[i].Step2,
            Step3: VUGSalaryDetails[i].Step3
        }]);
    } else {
        // otherwise, add it to the current entry:
        let previousEntry = this.processedData.get(VUGSalaryDetails[i].OrganizationName);
        previousEntry.add({
            Step1: VUGSalaryDetails[i].Step1,
            Step2: VUGSalaryDetails[i].Step2,
            Step3: VUGSalaryDetails[i].Step3
        });
        this.processedData.set(VUGSalaryDetails[i].OrganizationName, previousEntry);
    }
};

Now we have the processedData hashmap, over which we can loop in the html body with the keyvalue pipe:

<tbody *ngFor="let salaryVUGDetails of processedData | keyvalue">
    <tr>
        <th scope="col">{{salaryVUGDetails.key}}</th> <!-- the key is the organizationName -->
        <td>00,000</td>
        <td> <!-- first td are the rows of Step1's -->
            <p *ngFor="let row of salaryVUGDetails.value">{{row.Step1}<br></p>
        </td>
        <td> <!-- 2nd td are the rows of Step2's -->
            <p *ngFor="let row of salaryVUGDetails.value">{{row.Step2}<br></p>
        </td>
        <td> <!-- 3rd td are the rows of Step3's -->
            <p *ngFor="let row of salaryVUGDetails.value">{{row.Step3}<br></p>
        </td>
    </tr>
</tbody>

Now we probably need to add some css to make everything aligned good looking.

MojioMS
  • 1,583
  • 4
  • 17
  • 42
1

You can also add a new property "rowspan" to your data to use in .html [attr.rowspan]. For this, first create a new array transform your original "VUGSalaryDetails" adding a new property rowspan

dataFormated = this.VUGSalaryDetails.map((x, i) => ({
    ...x,
    rowspan:
      i == 0 ||
      this.VUGSalaryDetails[i - 1].OrganizationName != x.OrganizationName
        ? this.VUGSalaryDetails.filter(
            (f) => f.OrganizationName == x.OrganizationName
          ).length
        : -1,
  }));

Then you can use some like

  <tbody>
    <tr *ngFor="let salaryVUGDetails of dataFormated">
      <td
        mat-cell
        *ngIf="salaryVUGDetails.rowspan != -1"
        [attr.rowspan]="
          salaryVUGDetails.rowspan > 0 ? salaryVUGDetails.rowspan : null
        "
      >
        {{ salaryVUGDetails.OrganizationName }}
      </td>
      <td>{{ salaryVUGDetails.Step1 }}</td>
      <td>{{ salaryVUGDetails.Step2 }}</td>
      <td>{{ salaryVUGDetails.Step3 }}</td>
    </tr>
  </tbody>

A stackblitz

Eliseo
  • 50,109
  • 4
  • 29
  • 67
  • Thanks for your Reply , i will check and inform you – Rishf P Oct 10 '22 at 06:38
  • @RishfP, I just update new the stackblitz to show how work using a service. Un a service, that return an objervable (in the stackblitz I use "of", in general you will use an httpClient.get(...), you can define an observable in your component using rxjs operator map, to transform the response from the service. Then you can use pipe async – Eliseo Oct 10 '22 at 09:14
  • when add some more values in VUGSalaryDetails... it got error – Rishf P Oct 10 '22 at 10:10
  • See that all the data has almost "OrganizationName" as property – Eliseo Oct 10 '22 at 11:09