I've got an Angular component which does some fairly heavy calculations upon detecting changes.
@Component (
selector: 'my-table',
... 400+ lines of angular template ...
)
class MyTable implements OnDestroy, AfterContentInit, OnChanges {
...
@override
ngOnChanges(Map<String, SimpleChange> changes) {
log.info("ngOnChanges" + changes.keys.toString());
_buildTableContent();
}
...
}
This works beautifully when all the inputs are String
, int
, bool
; in other words, ngOnChanges
only triggers once these properties actually change.
I now need to add a custom renderer for one of the fields in order to render data that is not just a simple String
and I do it using
@Input("customRenderer") Function customRenderer;
The customRenderer
function will now decide if it should return the value as is or if the value is an object / list, extract certain values out of it and return a readable String instead of just Instance of ___
;
As soon as I add this @Input("customRenderer")
, ngOnChanges
fires the whole time even though that function reference hasn't changed.
Is there a way I can tell Angular to not trigger change detection on certain fields after the initial value is set?
A quick hack would be to just have an if-statement in the ngOnChanges
function that checks if customRenderer
is the only change, but change detection will continue to trigger which feels inefficient.
Does Angular have a hook I can override that will basically say, if field is customRenderer
, do not trigger change detection, otherwise do normal change detection?
Update based on @pankaj-parkar's answer:
@Component (
selector: 'my-table',
... 400+ lines of angular template ...
)
class MyTable implements OnDestroy, AfterContentInit, OnChanges, DoCheck {
...
final ChangeDetectorRef cdr;
int renderOldValue = 0;
@Input() int render = 0;
MyTable(this.cdr);
@override
ngOnChanges(Map<String, SimpleChange> changes) {
log.info("ngOnChanges" + changes.keys.toString());
_buildTableContent();
}
@override
ngDoCheck() {
if (renderOldValue != render) {
cdr.reattach();
cdr.detectChanges();
cdr.detach();
renderOldValue = render;
}
}
@override
ngAfterContentInit() {
// detach table from angular change detection;
cdr.detach();
...
}
...
}
Now the idea is to call render++
to manually trigger change detection
<my-table
(change)="change(\$event)"
(click2)="editResource(\$event)"
[custom]="['tags', 'attributes']"
[customRenderer]="customRenderer"
[data]="data ?? []"
[debug]="true"
[editable]="enableQuickEdit ?? false"
[loading]="loading ?? true"
[render]="render ?? 0"
[rowDropdownItems]="rowDropdownItems"
[tableDropdownItems]="tableDropdownItems ?? []">
<column *ngFor="let column of visibleColumns ?? []"
[editable]="column.editable"
[field]="column.field"
[title]="column.title">
</column>
</my-table>
Doesn't make a difference though ...