`ngDoCheck` is an Angular lifecycle method for custom change checks in a directive or component. It is useful when items are added to, removed from, or replaced within a collection: those changes do not invoke an iterating directive’s `ngOnChanges` method. `ngDoCheck` runs whenever Angular detects a change in the application, so the check must be inexpensive and updates should happen only when needed. section 15.3.4
An iterator that does too much work
A structural iterator can call `updateContent()` from both `ngOnInit()` and `ngDoCheck()`. If `updateContent()` clears its `ViewContainerRef` and recreates an embedded view for every item, even an unrelated change elsewhere in the application rebuilds the displayed collection. Restoring a product form alongside the table makes those repeated calls apparent while interacting with the form. section 15.3.4
Listing 15.15. Using ngDoCheck in the iterator.directive.ts File in the src/app folder
import { Directive, ViewContainerRef, TemplateRef, Input}
from "@angular/core";
import { interval } from "rxjs";
@Directive({
selector: "[paForOf]"
})
export class PaIteratorDirective {
constructor(private container: ViewContainerRef,
private template: TemplateRef<Object>) { }
@Input("paForOf")
dataSource: any;
ngOnInit() {
this.updateContent();
}
ngDoCheck() {
console.log("ngDoCheck Called");
this.updateContent();
}
private updateContent() {
this.container.clear();
for (let i = 0; i < this.dataSource.length; i++) {
this.container.createEmbeddedView(this.template,
new PaIteratorContext(this.dataSource[i],
i, this.dataSource.length));
}
}
}
class PaIteratorContext {
odd: boolean; even: boolean;
first: boolean; last: boolean;
constructor(public $implicit: any,
public index: number, total: number ) {
this.odd = index % 2 == 1;
this.even = !this.odd;
this.first = index == 0;
this.last = index == total - 1;
// interval(2000).subscribe(() => {
// this.odd = !this.odd; this.even = !this.even;
// this.$implicit.price++;
// })
}
}
The initial iterator logs each `ngDoCheck` call and rebuilds all its embedded views. Use it to identify the work that must not run unconditionally. section 15.3.4
A more selective iterator creates an `IterableDiffer` for its data source in `ngOnInit()`. During `ngDoCheck()`, it calls `diff(this.dataSource)` and processes records only when the result is not null. The addition example uses `forEachAddedItem()` and each record’s `item` and `currentIndex` to create views; handling deletion requires processing removals too. The differ separates frequent checking from changes that actually require a view update. section 15.3.4
Table 15.4. The IterableChanges methods and properties
|
Name
|
Description
|
|
forEachItem(func)
|
This method invokes the specified function for each object in the collection.
|
|
forEachPreviousItem(func)
|
This method invokes the specified function for each object in the previous version of the collection.
|
|
forEachAddedItem(func)
|
This method invokes the specified function for each new object in the collection.
|
|
forEachMovedItem(func)
|
This method invokes the specified function for each object whose position has changed.
|
|
forEachRemovedItem(func)
|
This method invokes the specified function for each object that was removed from the collection.
|
|
forEachIdentityChange(func)
|
This method invokes the specified function for each object whose identity has changed.
|
The `IterableChanges` method table distinguishes added, removed, moved, and identity-changed items when deciding which updates an iterator must handle. section 15.3.4
Refreshing a product table
A product-table component uses an `IterableDiffer` to check repository products inside `ngDoCheck()`. When the collection changes, it refreshes its `MatTableDataSource<Product>` so the Angular Material table reflects the repository. This applies the same hook to a component rather than a structural directive. section 7.5.3
Use `ngDoCheck` to decide whether work is necessary, not as a reason to repeat that work on every call. Conventional change detection still applies to directives whose data source is read from a signal in the described setup. section 15.3.4
