AngelPoyel
AngelPoyel

Reputation: 160

Why ngFor with filter pipe cause infinite loop?

i have this situation. CheckboxesComponent


    <section
        *ngFor="let group of model.groups | myfilter:term; let index = index">
        <div>
            <mat-checkbox
                        [checked]="group.allChecked"
                        [ngModel]="group.allChecked"
                        color="primary">
                {{ group.name }}
            </mat-checkbox>
        </div>
        <div>
            <ul>
                <li *ngFor="let checkbox of groups.checkboxes;">
                    <mat-checkbox
                        [checked]="checkbox.check"
                        [(ngModel)]="checkbox.check"
                        color="primary">
                        {{ checkbox.displayName }}
                    </mat-checkbox>
                </li>
            </ul>
        </div>
    </section>


In a second component i have

<mat-form-field
  appearance="outline">
  <mat-label>
    Search by
  </mat-label>
    <input
      matInput
      type="text"
      [(ngModel)]="filter">
    <mat-icon matPrefix fontIcon="icon-search"></mat-icon>
</mat-form-field>
    
<app-checkbox-group
   [datasource]="claims"
   [term]="filter"
>
</app-checkbox>

and this pipe

@Pipe({
  name: 'roleFilter',
  pure: false
})
export class myfilter implements PipeTransform {

  transform(groups: [], term: string): [] {
    if (!term) {
      return groups;
    }
    return groups
            .map(obj => {
                  return Object.assign({}, obj, {
                    checkboxes: obj.checkboxes.filter(el => el.displayName.includes(term))
                  })
                
            })
            .filter(obj => obj.checkboxes.length > 0)
  }
}

and groups is a dataset like this

[
    {
      name: 'Group 1',
      allChecked: false,
      isIndeterminate: false,
      checkboxes: [
        {
          check: true,
          displayName: 'first',
          name: 'first',
          id: '1',
          isMandatory: false
        },
        {
          check: false,
          displayName: 'second',
          name: 'second',
          id: '2',
          isMandatory: false
        },
        {
          check: false,
          displayName: 'third',
          name: 'third',
          id: '3',
          isMandatory: false
        },
        {
          check: false,
          displayName: 'fourth',
          name: 'fourth',
          id: '4',
          isMandatory: false
        },
        {
          check: false,
          displayName: 'fifth',
          name: 'fifth',
          id: '5',
          isMandatory: false
        },
        {
          check: false,
          displayName: 'sixth',
          name: 'sixth',
          id: '6',
          isMandatory: false
        },
        {
          check: false,
          displayName: 'seventh',
          name: 'seventh',
          id: '7',
          isMandatory: false
        },
        {
          check: false,
          displayName: 'eighth',
          name: 'eighth',
          id: '8',
          isMandatory: false
        },
      ]
    }
  ]

When i start typing on the input filter, to reduce the dataset, if i start typing with a letter that not match with any displayName all groups are hidden and it's work like expected. The problem appears when i start typing with a letter that match with some of the displayName property of the checkboxes. I don't understand why but all page freeze and the map function is called infinite times.

The problem seem to be in Object.assign in the map method. Because if i change this line with obj.checkboxes = checkboxes: obj.checkboxes.filter(el => el.displayName.includes(term)) it works but replace the original checkboxes with the filtered one.

Upvotes: 1

Views: 355

Answers (1)

AngelPoyel
AngelPoyel

Reputation: 160

In accordion to @Andrei comment

try to add trackByIndex(idx) {return idx;} method and pass it to both ngFor insatnces like this *ngFor="let checkbox of groups.checkboxes; trackBy: trackByIndex"

The solution was using the trackBy pipe on both *ngFor directives.

Upvotes: 1

Related Questions