Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Angular: update Angular Change Detection Specifics section #5220

Merged
merged 3 commits into from
Jun 21, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,189 @@ Angular activates change detection on each property change. This approach backfi

sergepilipchuk marked this conversation as resolved.
Show resolved Hide resolved
<!-- 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 workaround this behavior, implement one of the following approaches:
sergepilipchuk marked this conversation as resolved.
Show resolved Hide resolved

**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 the custom [Angular pipe](https://angular.io/guide/pipes-custom-data-trans).**
sergepilipchuk marked this conversation as resolved.
Show resolved Hide resolved

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

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

@Pipe({name: 'columnsPipe'})

sergepilipchuk marked this conversation as resolved.
Show resolved Hide resolved
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>
`,
})

sergepilipchuk marked this conversation as resolved.
Show resolved Hide resolved
To workaround this behavior, do one of the following:
export class AppComponent {
columnsOption = GridColumnsOption.PersonalDetails;
}

- Return an object reference, not a new object, from the function:
**Cache a returned value of the component’s method (for example, you can use universal apply pipe).**
sergepilipchuk marked this conversation as resolved.
Show resolved Hide resolved

<!-- 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' })

sergepilipchuk marked this conversation as resolved.
Show resolved Hide resolved
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']
})

sergepilipchuk marked this conversation as resolved.
Show resolved Hide resolved
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 you to use an arrow function with this approach.
sergepilipchuk marked this conversation as resolved.
Show resolved Hide resolved