Amrit
Amrit

Reputation: 2175

Run Angular change detection only once and stop detecting changes for that component

I need to detect changes in angular only once when the component is loaded or when route has changed and i want to stop detecting changes after that.

Actually I need to show and hide functionality depending on user role. So i have many *ngIf in a single html template but i need to check *ngIf condition only once when the template is loaded first time and stop detecting changes after that because it is affecting performance.

I want the page to be like static after single time change detection.

For example :

       <li *ngIf="doesHavePermission('templateName')">
       </li>

should check once but what I am seeing is that it is checking the change many times for single *ngIf and I have many *ngIf like this:

I found markForCheck() and detach() in this angular document https://angular.io/api/core/ChangeDetectorRef.

But what they are doing is that they are either allowing all change detection or none at all,

And I need to detect changes only once and stop after that.

Can we do this single time change detection in angular?

Or is there a better way to handle the scenerio?

Upvotes: 5

Views: 8920

Answers (2)

Viacheslav Muzyka
Viacheslav Muzyka

Reputation: 341

You can just use detach method for ChangeDetectorRef injector to remove current component from Change Detection cycle. You can always call reattach method or manually call detectChanges to make the quickly run through the changes.

As for me it's the most reliable way.

But pay attention that it always will turn off change detection for all children!

Upvotes: 2

J. S.
J. S.

Reputation: 2374

When you use a function call inside of *ngIf then angular calls this function every time when change detection occurs. It doesn't matter if this changeDetection is triggered outside or inside your component, but angular cannot know if the return value of the function has changed before it has called this function.

So it is not a good approach to use function calls inside *ngIf in general.

Alternatives:

Use normal attributes inside your component:

instead of 
<div *ngIf="checkCondition()"></div>

use this

<div *ngIf="condition"></div>

@Component(...)
class MyComponent {
 condition= false;

 checkCondition() {
  if(something) {
   this.condition = true;
  }
 }
}

With this approach you can handle better when a condition has changed and call the function manually. Instead of just use an attribute you can also use a map:

@Component(...) 
class MyComponent{
  conditions: { [key: string]: boolean }

  ngOnInit() {
   condition = {
    template1: true,
    template2: false
   }
  }
}

<div *ngIf="conditions['template1']"></div>

In combination with ChangeDetectionStrategy.OnPush you can minimize the changedetection as onPush only triggers change detection when input params has changed. It basically means that change detection from a parent does not trigger change detection of a child.

If you combine these two approaches you should get minimum changedetection:

@Component({
...
changeDetection: ChangeDetectionStrategy.OnPush
}) 
    class MyComponent{
      @Input() conditions: { [key: string]: boolean }
}

Here is a good article for further reading: https://medium.com/showpad-engineering/why-you-should-never-use-function-calls-in-angular-template-expressions-e1a50f9c0496

Upvotes: 6

Related Questions