bug in angular when data bing inside ngfor loop

Viewed 317

why every time i use a ngFor, the loops runs 4 times? and how to stop it? can someone explain to me what is happening?

here is a little sample.

3 Answers

The reason that the iShouldrepeatOneTime method is called 4 times is because of Angular's default ChangeDetectionStrategy. By default, every time there is a change in your component, in this case for every loop, Angular will check your whole component for changes. The only way for Angular to know whether the return value of iShouldrepeatOneTime has changed is by calling it.

So how do you get around this? There are two choices that come to mind:

  1. Use OnPush ChangeDetectionStrategy, or
  2. Ensure that you do not bind to methods in your template for reasons other than event emitters. Bind to properties instead.

I will expand on my second point. Imagine you had a property in your component someValue and a method calculateSomeValue() as follows:

someValue = 'foo';

calculateSomeValue(): string {
  return 'bar';
}

In your template, having {{ someValue }} is more efficient than {{ calculateSomeValue() }} because in the former approach Angular already knows if the value of the property has changed and if it needs to be updated in the view. In the latter approach, Angular needs to call the method first before it knows if it needs to update the value in the view.

There are no bugs here! You have 4 outputs because your array has 4 objects. If you want to iterate values by specific field, you can add pipe:

1) add this pipe to the end of your app.component

import { Pipe, PipeTransform } from "@angular/core";

@Pipe({
  name: "mymap"
})
export class ArrayMapPipe  implements PipeTransform {
  transform(array: any, field: string): any[] {
    if (!Array.isArray(array)) {
      return;
    }
    return array.filter((e: any) => e.camp2 === field);
  }
}

2) import the pipe to the app.module

import { AppComponent, ArrayMapPipe } from './app.component';
...
declarations: [ AppComponent, HelloComponent, ArrayMapPipe ]

3) you can use it like this:

<div *ngFor="let key of array | mymap:'orange'">
    <div>
        <span class="teste">{{key | json}} </span>
    </div>
</div>

That is not a Bug. It is not good practise using function calls in value bindings. In such case function will be called every time when Angular runs change detection. You should do it as follows.

<div>{{ someValue }}</div>


export class AppComponent {

  someValue;

  ngOnInit() {
    this.someValue = this.someMethod();
  }

  someMethod(){
    const someValue = 2;
    return someValue;
  }
}

Read more about Angular DOM update mechanism.

Related