How is Angular * ngFor loop implemented?
Wondering how the Angular directive *ngFor
actually works under the hood? I would like to know the whole process that occurs when I use a directive.
For downvoters : I've seen the ng-for-of file , although there is none using the passed array *ngFor
, such as the join()
method I know is called. Thanks for the support :) Here is a plunker that shows the behavior: https://plnkr.co/edit/IXVxWrSOhLBgvSal6PWL?p=preview
source to share
Here's a high-level overview. Let's say you have defined your template like this:
<span *ngFor="let item of items">{{item}}</span>
Then it gets converted to the compiler like this:
<ng-template let-item [ngForOf]="items">
<span>{{item}}</span>
</ng-template>
Angular then applies the directive ngForOf
to the template element. Since this main control is a template, it enters templateRef
. It also introduces viewContainerRef
which acts like an anchor element and will be used to add DOM elements side by side:
constructor(
private _viewContainer: ViewContainerRef,
private _template: TemplateRef<NgForOfContext<T>>,
The directive defines ngForOf
as an input and then waits until it is initialized and makes a difference:
ngOnChanges(changes: SimpleChanges): void {
const value = changes['ngForOf'].currentValue;
this._differ = this._differs.find(value).create(this.ngForTrackBy);
Then, in each test run, it compares the values โโwith the previous values โโusing this:
ngDoCheck(): void {
if (this._differ) {
const changes = this._differ.diff(this.ngForOf);
if (changes) this._applyChanges(changes);
}
}
If the values โโare changed, changes are applied that do the following:
1) generates an inline view context for each item in items
context = new NgForOfContext<T>(null !, this.ngForOf, -1, -1)
2) creates an inline view in this context with templateRef
that effectively renders the new value to the DOM
this._viewContainer.createEmbeddedView(
this._template, context , currentIndex);
3) adds appropriate values โโto the context
viewRef.context.index = i;
viewRef.context.count = ilen;
viewRef.context.$implicit = record.item;`
Now, your question is:
although it doesn't explain why the e..g join () method is called on the array passed
It calls the function normalizeDebugBindingValue
here because your application is in development mode:
function normalizeDebugBindingValue(value: any): string {
try {
// Limit the size of the value as otherwise the DOM just gets polluted.
return value != null ? value.toString().slice(0, 30) : value;
^^^^^^^^^^^^^^^
} catch (e) {
return '[ERROR] Exception while trying to serialize the value';
}
}
If you turn on production mode, this function will no longer be called, check the plunker .
source to share