0

I understand that the change detection will fire for OnPush marked component if the input property changes (there are others way too).

But I don't have an input property in my child component and I have a service injected into my component. I have subscribed the observable exposed by the service inside this child component. Now inside the subscribe callback method I change one of my child component's private property's value. The template of the component is bonded to this property.

So the problem is when the observer publishes an event my subscriber callback is called, and it changes the property value but the view doesn't reflect the changes. The UI only updates when I click somewhere in my page.

changeDetection: ChangeDetectionStrategy.OnPush

Update 1: Plunker added

thinkmmk
  • 487
  • 1
  • 8
  • 22
  • Have you tried to use async pipe or `cdRef.markForCheck()`? And where is your code? – yurzui Apr 30 '17 at 20:23
  • I can't use asynchronous pipe as my template is binded to a private property of component example a string. And CDR.markForCheck() I read but isn't it an overkill as it will go back till the anscetor root component by firing CD? I don't know how to post a plunker, will Google and add shortly. Thanks. – thinkmmk Apr 30 '17 at 20:31
  • No, `markForCheck` doesn't go back to the ancestor root. That's `ApplicationRef.tick()`. `markForCheck` makes the component not being skipped on the next change detection turn. – Günter Zöchbauer Apr 30 '17 at 20:32
  • Actually I went through this, here the last paragraph of the answer says it fires till root http://stackoverflow.com/questions/35386822/changedetectionstrategy-onpush-and-observable-subscribe-in-angular-2 – thinkmmk Apr 30 '17 at 20:40
  • don't bind to private prop - it is not AOT compatible. – Julia Passynkova Apr 30 '17 at 20:53
  • you'll need to trigger change detection manually. Nothing wrong with that in your use case :) take a look here: http://stackoverflow.com/questions/34827334/triggering-angular2-change-detection-manually – Ahmed Musallam May 01 '17 at 01:34

1 Answers1

2

So, the comments are totally right. markForCheck() will cause it to go up to the root, but that's not a bad thing..

If your app goes: root > section > page > area > row > list and you make changes on your list then you would want to notify the parent items that changes have happened. Maybe you need to grow bigger now that more data is loaded, or trigger a scroll, or all sorts of stuff.

Remember though that you'll have to wait for a tick and if you're using onPush() on the parents as well without being notified that a child has changed with markForCheck() the detection will never reach your child, that's why it goes all the way.

The other method is manually triggering with detectChanges() This will run only on the local component and treats the node that called detectChanges() as the root..

Also, if you're displaying any property of your component it isn't technically Private. Javascript will allow it of course but test suites and I think even the compiler will complain. if you for whatever MUST do it, display it with a public getter.. like this:

Private _mySuperSecret: 'I am Batman';
Public get mySecret() { return this._mySuperSecret; };
Dennis Smolek
  • 8,480
  • 7
  • 30
  • 39
  • I have edited my question to add plunker. Also in the plucker when I use detectChanges() it works, but in my actual code which I can't share detectChanges() doesn't works. But markForChanges() works. I am using angular 2.4.0 version. Also I didn't understand the 3rd paragraph of your answer, can you please help me in understanding that. I am confused about the behaviors of my app now. – thinkmmk May 01 '17 at 06:23
  • 1
    Yeah the sentence kinda sucks. What I meant is say you have a parent component(A) that is `onPush()` and a child (B) that is `onPush()` that again has a child (C) that is `onPush()` and this is where you trigger a change. The reason `markForCheck()` goes up the tree to root regardless is the detector starts at the **root** and says "A do you have changes?" if it doesn't, it skips it, and the changes on child C would never be detected. Therefore, they mark all the parents to be tested so the actually changed child will be detected and updated – Dennis Smolek May 02 '17 at 00:12
  • If you meant about the `private` thing, `private` is reserved for internal data. It's generally frowned upon to expose it in any way, including the view layer of your component. Javascript of course doesn't care but Typescript can and the Angular Compiler does too. When you move to the current 4.X branch it would likely throw errors. Either switch it to `public` or create a public read-only function like my example – Dennis Smolek May 02 '17 at 00:15
  • thanks for the explanation. markForChanges() works in my code but not detect changes(). Any reason that you can think of why. Because above pic code works for both but in my actual code only markForChanges () works. – thinkmmk May 02 '17 at 02:19