I try to understand how the *ngFor
directive of Angular works behind the scene.
Something I wanted to know was if the iterable passed to the directive was interpreted at each loop iteration (like the condition of the JS for
loop) or if angular creates a "cache"-like variable with that value. To answer this question, I did a ngFor
that has a method returning an array as the iterable object.
<li *ngFor="let data of test(dataArr)">{{data}}</li>
The related TS :
dataArr = [1,2,3,4];
iterationNb = 1;
test(arr) {
console.log('has iterated', this.iterationNb++);
return arr.filter(i => true);
}
And here what I get in the console :
has iterated 1
has iterated 2
has iterated 3
has iterated 4
If you need the angular project, here is my example app used for my tryouts : https://stackblitz.com/edit/angular-3kmyyw
That's great, I see that angular just call the method at each iteration. But that's where it starts to be complex for me...
I then tried to change the ref array dataArr
used by the method by adding some other values in it like :
dataArr = [1,2,3,4,5,6,7];
But now I still have in my console 4 iterations... Then I tried with
dataArr = [1,2];
and booom still 4 iterations...
So now I'm very confused about this... Why do I have always 4 iteration ? The first attempt was just luck of having choosen 4 items in my array and in fact it has nothing to do with that ? I tried to look at the angular ngfor source code but I'm still not that ninja that understands it without explanations...
Thanks
That's great, I see that angular just call the method at each iteration. But that's where it starts to be complex for me...
You are not seeing iterations. Angular called the method each time the DOM was rendered. It has nothing to do with how many elements were in the array. It was just by luck you saw it count to 4.
<li *ngFor="let data of test(dataArr)">
The above is executed once per rendering pass. The *ngFor
directive breaks down the expression into two variables. A reference to the current iterable, and a reference to the source iterator.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#Iterators
ngFor only needs to assign the source iterator once per rendering pass. In your expression the test()
function returns the iterator (which happens to be an array). It will take the next() value from the iterator and assign it to the data
variable which will be exposed in the template.
ngFor will keep calling next() until it reaches the end of the iterator. For each iteration ngFor checks if there is a DOM element that should be inserted, updated or removed. It knows what data goes with which DOM element using a trackBy function.
https://medium.com/@ramy_ali/improving-angular-ngfor-performance-through-trackby-ae4cf943b878