What's the difference between markForCheck() and detectChanges() Ask Question

What's the difference between markForCheck() and detectChanges() Ask Question

What is the difference between ChangeDetectorRef.markForCheck() and ChangeDetectorRef.detectChanges()?

I only found information on SO as to the difference between NgZone.run(), but not between these two functions.

For answers with only a reference to the doc, please illustrate some practical scenarios to choose one over the other.

ベストアンサー1

detectChanges() : void

Checks the change detector and its children.

It means, if there is a case where any thing inside your model (your class) has changed but it hasn't reflected the view, you might need to notify Angular to detect those changes (detect local changes) and update the view.

Possible scenarios might be :

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);
 }

3- 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!

You'll definitely come across this error :P .

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.


From the docs

markForCheck() : void

すべての ChangeDetectionStrategy 祖先をチェック対象としてマークします。

これは主に、コンポーネントのChangeDetectionStrategy がOnPushの場合に必要になります。

OnPush 自体は、次のいずれかが発生した場合にのみ変更検出を実行することを意味します。

1- コンポーネントの @input の 1 つが新しい値に完全に置き換えられた場合、または簡単に言えば、@Input プロパティの参照が完全に変更された場合。

したがって、コンポーネントのChangeDetectionStrategyがOnPushの場合、次のようになります。

   var obj = {
     name:'Milad'
   };

そして、次のように更新/変更します。

  obj.name = "a new name";

これにより、 obj参照は更新されないため、変更検出は実行されず、ビューは更新/変更を反映しません。

この場合、Angular にビューをチェックして更新するように手動で指示する必要があります (markForCheck)。

したがって、これを実行した場合:

  obj.name = "a new name";

次の操作を行う必要があります:

  this.cd.markForCheck();

代わりに、以下の変更検出が実行されます。

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

これにより、以前の obj が新しい{};に完全に置き換えられました。

2- クリックなどのイベントが発生したか、子コンポーネントのいずれかがイベントを発行しました。

次のようなイベント:

  • クリック
  • キーアップ
  • サブスクリプションイベント

つまり、簡単に言うと:

  • detectChanges()Angular が変更検出を実行した後にモデルを更新した場合、または更新が Angular の世界でまったく行われていない場合に使用します。

  • markForCheck()OnPush を使用しており、一部のデータを変更して をバイパスしている場合、またはsetTimeoutChangeDetectionStrategy内でモデルを更新した場合に使用します。

おすすめ記事