Skip to content

Commit

Permalink
Angular: update Angular Change Detection Specifics section (#5220) (#…
Browse files Browse the repository at this point in the history
…5232)

* Angular: update Angular Change Detection Specifics section

* Apply suggestions from code review



* Apply suggestions from code review



---------

Co-authored-by: Ilya Vinogradov <[email protected]>
Co-authored-by: Albert Totten <[email protected]>
  • Loading branch information
3 people authored Jun 21, 2023
1 parent 60e8b5d commit 2ed8d58
Showing 1 changed file with 153 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,185 @@ Angular activates change detection on each property change. This approach backfi

<!-- tab: app.component.ts -->
import { Component } from '@angular/core';

enum GridColumnsOption {
PersonalDetails = 0,
JobDetails = 1,
}

@Component({
selector: 'app-root',
selector: 'app-component',
template: `
<dx-data-grid
[columns]="getColumns()">
[columns]="getColumns(columnsOption)">
</dx-data-grid>
`,
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.**

<!-- tab: app.component.ts -->
import { Component } from '@angular/core';

enum GridColumnsOption {
PersonalDetails = 0,
JobDetails = 1,
}

@Component({
selector: 'app-component',
template: `
<dx-data-grid
[columns]="columns[columnsOption]">
</dx-data-grid>
`,
})

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).**

<!-- tab: app.component.ts -->
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: `
<dx-data-grid
[columns]="columnsOption | columnsPipe">
</dx-data-grid>
`,
})
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).**

<!-- tab: app.component.ts -->
import { Component } from '@angular/core';
import {
Component,
Pipe,
PipeTransform,
} from '@angular/core';
enum GridColumnsOption {
PersonalDetails = 0,
JobDetails = 1,
}

@Pipe({ name: 'apply' })
export class ApplyPipe<TArgs, TReturn> implements PipeTransform {
transform(func: ((...args: TArgs[]) => TReturn), ...args: TArgs[]): TReturn { return func(...args); }
}

@Component({
selector: 'app-root',
selector: 'app-component',
template: `
<dx-data-grid
[columns]="getColumns()">
[columns]="getColumns | apply: columnsOption">
</dx-data-grid>
`,
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:

<!-- tab: app.component.ts -->
import { Component, ChangeDetectionStrategy } from '@angular/core';

@Component({
// ...
changeDetection: ChangeDetectionStrategy.OnPush
})
// ...
[note]We recommend that you use an arrow function with this technique.

0 comments on commit 2ed8d58

Please sign in to comment.