angular整理

Angular 零碎知识整理(四) - detectChange

2020-02-19  本文已影响0人  肉桂猿

detectChanges()

  1. The change detector is detached from the view ( see detach )
  2. An update has happened but it hasn't been inside the Angular Zone, therefore, Angular doesn't know about it.
    Like when a third party function has updated your model and you want to update the view after that.
someFunctionThatIsRunByAThirdPartyCode(){
  yourModel.text = "new text";
}

Because this code is outside of Angular's zone (probably), you most likely need to make sure to detect the changes and update the view , thus :

myFunction(){
  someFunctionThatIsRunByAThirdPartyCode();
  // Let's detect the changes that above function made to the model which Angular is not aware of.
  this.cd.detectChanges();
}

NOTE :
There are other ways to make above work, in other words, there are other ways to bring that change inside Angular change cycle.

// You could wrap that third party function inside a zone.run :
myFunction(){
  this.zone.run(this.someFunctionThatIsRunByAThirdPartyCode);
}

//  You could wrap the function inside a setTimeout :
myFunction(){
  setTimeout(this.someFunctionThatIsRunByAThirdPartyCode, 0);
}

There are also cases where you update the model after the change detection cycle is finished , where in those cases you get this dreaded error :

"Expression has changed after it was checked";

This generally means :
(from Angular2 language) I saw an change in your model that was caused by one of my accepted ways ( events , XHR requests , setTimeout, and ... ) and then I ran my change detection to update your view and I finished it, but then there was another function in your code which updated the model again and I don't wanna run my change detection again because there is no dirty checking like AngularJS anymore :D and we should use one way data flow!

Couple of ways to fix it :
1- Proper way : make sure that update is inside the change detection cycle ( Angular2 updates are one way flow that happen once, do not update the model after that and move your code to a better place/time ).

2- Lazy way : run detectChanges() after that update to make Angular2 happy , this is definitely not the best way, but as you asked what are the possible scenarios , this is one of them.This way you're saying : I sincerely know you ran the change detection, but I want you to do it again because I had to update something on the fly after you finished the checking.

3- Put the code inside a setTimeout , because setTimeout is patched by zone and will run detectChanges after it's finished.


markForCheck()

This is mostly needed when the ChangeDetectionStrategy of your component is OnPush.

OnPush itself means, only run the change detection if any of these has happened :

  1. One of the @inputs of the component has been completely replaced with a new value , or simply put, if the reference of the @Input property has changed altogether .

So if ChangeDetectionStrategy of your component isOnPush and then you have :

var obj = {
  name:'Milad'
};

And then you update/mutate it like :

  obj.name = "a new name";

This will not update the obj reference ,hence the change detection is not gonna run, therefore the view is not reflecting the update/mutation.

In this case you have to manually tell Angular to check and update the view (markForCheck);

So if you did this :

obj.name = "a new name";

You need to do this:

this.cd.markForCheck();

Rather , bellow would cause a change detection to run :

obj = {
  name:"a new name"
};

Which completely replaced the previous obj with a new {};

  1. An event has fired, like a click or some thing like that or any of the child components has emitted an event.

Events like :

*   Click

*   Keyup

*   Subscription events

*   etc.

So in short :

The biggest difference between the two is that detectChanges() actually triggers change detection, while markForCheck() doesn't trigger change detection.

上一篇下一篇

猜你喜欢

热点阅读