diff --git a/concepts/40 Angular Components/20 Component Configuration Syntax/85 Angular Change Detection Specifics.md b/concepts/40 Angular Components/20 Component Configuration Syntax/85 Angular Change Detection Specifics.md index b07462fd12..89690b647b 100644 --- a/concepts/40 Angular Components/20 Component Configuration Syntax/85 Angular Change Detection Specifics.md +++ b/concepts/40 Angular Components/20 Component Configuration Syntax/85 Angular Change Detection Specifics.md @@ -2,65 +2,185 @@ Angular activates change detection on each property change. This approach backfi import { Component } from '@angular/core'; + + enum GridColumnsOption { + PersonalDetails = 0, + JobDetails = 1, + } @Component({ - selector: 'app-root', + selector: 'app-component', template: ` + [columns]="getColumns(columnsOption)"> `, - styleUrls: ['./app.component.css'] }) + export class AppComponent { - getColumns() { - return [ - { dataField: "firstName" }, - { dataField: "lastName" } - ]; + columnsOption = GridColumnsOption.PersonalDetails; + + getColumns(option: GridColumnsOption): string[] { + switch (option) { + case GridColumnsOption.PersonalDetails: + return [ + 'name', + 'address', + 'phone', + ]; + case GridColumnsOption.JobDetails: + return [ + 'name', + 'position', + 'salary', + ]; + default: + return []; + } } } In the code above, the `getColumns()` function returns an array of objects, but this array is created from scratch each time the function is called. This is what happens when you run this code: 1. The `getColumns()` function returns an array. -1. The array gets assigned to the `columns` property. This activates change detection. -1. When comparing the old and new `columns` values, the change detection mechanism calls `getColumns()` again and receives a different array. -1. The array gets assigned to the `columns` property, and the cycle repeats infinitely. +2. The array gets assigned to the `columns` property. This activates change detection. +3. When comparing the old and new `columns` values, the change detection mechanism calls `getColumns()` again and receives a different array. +4. The array gets assigned to the `columns` property, and the cycle repeats infinitely. + +To work around this behavior, implement one of the following techniques: + +**Use a component’s class field instead of a method.** + + + import { Component } from '@angular/core'; + + enum GridColumnsOption { + PersonalDetails = 0, + JobDetails = 1, + } + + @Component({ + selector: 'app-component', + template: ` + + + `, + }) + + export class AppComponent { + columnsOption = GridColumnsOption.PersonalDetails; + + columns = { + [GridColumnsOption.PersonalDetails]: [ + 'name', + 'address', + 'phone', + ], + [GridColumnsOption.JobDetails]: [ + 'name', + 'position', + 'salary', + ], + }; + } + +**Rewrite a component’s class method to a custom [Angular pipe](https://angular.io/guide/pipes-custom-data-trans).** + + + import { + Component, + Pipe, + PipeTransform, + } from '@angular/core'; + + enum GridColumnsOption { + PersonalDetails = 0, + JobDetails = 1, + } -To workaround this behavior, do one of the following: + @Pipe({name: 'columnsPipe'}) + export class ExponentialStrengthPipe implements PipeTransform { + transform(columnsOption: GridColumnsOption): string[] { + switch (option) { + case GridColumnsOption.PersonalDetails: + return [ + 'name', + 'address', + 'phone', + ]; + case GridColumnsOption.JobDetails: + return [ + 'name', + 'position', + 'salary', + ]; + default: + return []; + } + } + } + + @Component({ + selector: 'app-component', + template: ` + + + `, + }) + export class AppComponent { + columnsOption = GridColumnsOption.PersonalDetails; + } -- Return an object reference, not a new object, from the function: +**Cache the return value of the component’s method (for example, you can use a universal apply pipe).** - import { Component } from '@angular/core'; + import { + Component, + Pipe, + PipeTransform, + } from '@angular/core'; + + enum GridColumnsOption { + PersonalDetails = 0, + JobDetails = 1, + } + + @Pipe({ name: 'apply' }) + export class ApplyPipe implements PipeTransform { + transform(func: ((...args: TArgs[]) => TReturn), ...args: TArgs[]): TReturn { return func(...args); } + } @Component({ - selector: 'app-root', + selector: 'app-component', template: ` + [columns]="getColumns | apply: columnsOption"> `, - styleUrls: ['./app.component.css'] }) export class AppComponent { - _columns: [ - { dataField: "firstName" }, - { dataField: "lastName" } - ]; - getColumns() { - return this._columns; + columnsOption = GridColumnsOption.PersonalDetails; + + getColumns = (option: GridColumnsOption): string[] => { + switch (option) { + case GridColumnsOption.PersonalDetails: + return [ + 'name', + 'address', + 'phone', + ]; + case GridColumnsOption.JobDetails: + return [ + 'firstName', + 'position', + 'salary', + ]; + default: + return []; + } } } -- Switch change detection to the `OnPush` mode: - - - import { Component, ChangeDetectionStrategy } from '@angular/core'; - - @Component({ - // ... - changeDetection: ChangeDetectionStrategy.OnPush - }) - // ... +[note]We recommend that you use an arrow function with this technique.