How to stop rendering of an item if it has already been iterated - ngFor, ngIf, Angular 16

59 Views Asked by At

I have an array of objects which i have to iterate through and present some data (rafale and quantities of raw, semi-finished and finished parts) in the table.

My array of objects is as follows:

tableMongoData = [
    {
      ref: '322416730R',
      type: 'RAW',
      rafale: [
        {
          name: '14x63',
          refs: [
            {
              type: 'PB',
              ref: '8201729087',
              partQty: '1.502',
              rowspan: 1,
            },
            {
              type: 'PN',
              ref: '8201729088',
              partQty: '921',
              rowspan: 1,
            },
            {
              type: 'PA',
              ref: '322419484R',
              partQty: '112',
              rowspan: 1,
            },
          ],
        },
        {
          name: '14x69',
          refs: [
            {
              type: 'PB',
              ref: '8201729081',
              partQty: '761',
              rowspan: 1,
            },
            {
              type: 'PN',
              ref: '8201729083',
              partQty: '295',
              rowspan: 1,
            },
            {
              type: 'PA',
              ref: '322410929R',
              partQty: '868',
              rowspan: 1,
            },
          ],
        },
      ],
      partQty: '1.467',
      rowspan: 2,
    },
    {
      ref: '322419487R',
      type: 'RAW',
      rafale: [
        {
          name: '15x58',
          refs: [
            {
              type: 'PB',
              ref: '8201729084',
              partQty: '2.977',
              rowspan: 1,
            },
            {
              type: 'PN',
              ref: '8201729085',
              partQty: '2.627',
              rowspan: 1,
            },
            {
              type: 'PA',
              ref: '322414657R',
              partQty: '397',
              rowspan: 1,
            },
          ],
        },
      ],
      partQty: '7.555',
      rowspan: 1,
    },
  ];

My HTML file is as follows:

<div class="container">
  <table class="table table-responsive mt-5 caption-top">
    <caption></caption>
    <thead class="align-middle table-group-divider">
      <tr>
        <th class="text-center" scope="col">IDENTIFICAÇÃO PEÇA</th>
        <th class="text-center" scope="col">PEÇA EM BRUTO</th>
        <th class="text-center" scope="col">PEÇA BRANCA</th>
        <th class="text-center" scope="col">PEÇA NEGRA</th>
        <th class="text-center" scope="col">PEÇA ACABADA</th>
      </tr>
    </thead>
    <tbody class="table-group-divider">
      <ng-container *ngFor="let refRaw of tableMongoData">
        <tr *ngFor="let rafale of refRaw.rafale">
          <th class="text-center" scope="row">{{ rafale.name }}</th>
          <td
            [attr.rowspan]="refRaw.rowspan"
            class="text-center align-middle"
            tabindex="0"
            data-html="true"
            data-bs-toggle="tooltip"
            data-bs-placement="top"
            data-bs-title="Referência: "
          >
            {{ refRaw.partQty }}
          </td>
        </tr>
      </ng-container>
    </tbody>
  </table>
</div>

My problem is that the quantity of the first RAW reference is rendered twice (picture TABLE).

I think it has to do with the fact that in my *ngFor inside a i iterate through 3 rafale references, thus a inside that is rendered 3 times.

Is there any way of stopping iteration knowing that the first reference has already been iterated and its quantity has already been rendered?

Working example in

I've already tried to use *ngIf in order to check whether the reference has already been iterated, and trackBy functionality but without success. There must be something wrong with the way i implement the code.

3

There are 3 best solutions below

0
Anton Fedak On BEST ANSWER

Solution was inspired by the comment of Prabath Udayanga.

If I'm able to define whether I want to print a value or not, using *ngIf directive, I should be able, using *ngIf directive, to tell the table when to create a data cell.

I made the following modification to code:

<tbody class="table-group-divider">
        <ng-container *ngFor="let refRaw of tableMongoData">
            <tr *ngFor="let rafale of refRaw.rafale; let i = index">
                <th class="text-center" scope="row">{{ rafale.name }}</th>
                <td *ngIf="i === 0" [attr.rowspan]="refRaw.rowspan" class="text-center align-middle" tabindex="0"
                    data-html="true" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Referência: ">
                    {{ refRaw.partQty }}</td>
                <td *ngFor="let ref of rafale.refs" [attr.rowspan]="ref.rowspan" class="text-center align-middle"
                    tabindex="0" data-html="true" data-bs-toggle="tooltip" data-bs-placement="top"
                    data-bs-title="Referência: ">
                    {{ ref.partQty }}
                </td>
            </tr>
        </ng-container>
    </tbody>

In tag I've added a condition based on an index of rafale: *ngIf="i === 0". This means that the cell data is created only for the first instance of the rafale. Since I always have at least 1 rafale identifiction, I always create a cell data for an existing rafale. When I have multiple rafales per part reference, I create only one cell data and rowspan attribute takes care of the rest.

Working code is on the following link: Working code

2
MGX On

It looks to me that your data model is to blame. If you wish to make it in a simple fashion, move your qty and rowspan to your rafale item, and if there's no property, don't display it.

Here is a working example :

https://stackblitz.com/edit/angular-ivy-q9z2xm?file=src%2Fapp%2Fapp.component.html,src%2Fapp%2Fapp.component.ts%3AL94,src%2Fapp%2Fapp.component.css

tableMongoData = [
    {
      ref: '322416730R',
      type: 'RAW',
      rafale: [
        {
          name: '14x63',
          partQty: '1.467',
          rowspan: 2,
          refs: [
            { type: 'PB', ref: '8201729087', partQty: '1.502', rowspan: 1 },
            { type: 'PN', ref: '8201729088', partQty: '921', rowspan: 1 },
            { type: 'PA', ref: '322419484R', partQty: '112', rowspan: 1 },
          ],
        },
        {
          name: '14x69',
          refs: [
            { type: 'PB', ref: '8201729081', partQty: '761', rowspan: 1 },
            { type: 'PN', ref: '8201729083', partQty: '295', rowspan: 1 },
            { type: 'PA', ref: '322410929R', partQty: '868', rowspan: 1 },
          ],
        },
      ],
    },
    {
      ref: '322419487R',
      type: 'RAW',
      rafale: [
        {
          name: '15x58',
          partQty: '7.555',
          rowspan: 1,
          refs: [
            { type: 'PB', ref: '8201729084', partQty: '2.977', rowspan: 1 },
            { type: 'PN', ref: '8201729085', partQty: '2.627', rowspan: 1 },
            { type: 'PA', ref: '322414657R', partQty: '397', rowspan: 1 },
          ],
        },
      ],
    },
  ];
1
Prabath Udayanga On

This will fix the issue before printing the qty you can check the iteration number using the index if iteration is not the first then stop printing the quantity. Here is the example code and working demo

<div class="container">
  <h2>Stock</h2>
</div>

<div class="container">
  <table class="table table-responsive mt-5 caption-top">
    <caption></caption>
    <thead class="align-middle table-group-divider">
      <tr>
        <th class="text-center" scope="col">IDENTIFICAÇÃO PEÇA</th>
        <th class="text-center" scope="col">PEÇA EM BRUTO</th>
        <th class="text-center" scope="col">PEÇA BRANCA</th>
        <th class="text-center" scope="col">PEÇA NEGRA</th>
        <th class="text-center" scope="col">PEÇA ACABADA</th>
      </tr>
    </thead>
    <tbody class="table-group-divider">
      <ng-container *ngFor="let refRaw of tableMongoData">
        <tr *ngFor="let rafale of refRaw.rafale; let i = index" >
          <th class="text-center" scope="row">{{ refRaw.rafale[0].name }}</th>
          <td
            [attr.rowspan]="refRaw.rowspan"
            class="text-center align-middle"
            tabindex="0"
            data-html="true"
            data-bs-toggle="tooltip"
            data-bs-placement="top"
            data-bs-title="Referência: "
          >
            {{ i <= 0 ? refRaw.partQty : '' }}
          </td>
          <!-- <ng-container *ngFor="let rafale of refRaw.rafale">
            <ng-container *ngFor="let ref of rafale.refs">
              <td
                [attr.rowspan]="ref.rowspan"
                class="text-center align-middle"
                tabindex="0"
                data-html="true"
                data-bs-toggle="tooltip"
                data-bs-placement="top"
                data-bs-title="Referência: "
              >
                {{ ref.partQty }}
              </td>
            </ng-container>
          </ng-container> -->
        </tr>
      </ng-container>
    </tbody>
  </table>
</div>