Angular onpush change detection strategy with primitive values












2















may be I am misunderstanding the changeDetection strategy in angular.



Here is Description:




  • I have 2 Sibling components (S1 and S2)

  • Think both the components as widget on which some graphical data being displayed

  • When loaded I want to display data on both the component initially. (For this I am using behaviour subject)

  • From S1 I want to notify S2 to trigger a http service call. (I have used behaviour subject and calling .next on click of a button in S1. I am subscribing to same observable in S2 to get the data)

  • My S2 component is registered with onPush change detection strategy.

  • I am using loading text while http service call is in progress and then removing the text after complete using ngIf using primitive variable this.loading=true/false


Now My problem is when App loads initially I can see loading... text on S2 widget and then data gets populated.



But when I click on the notify sibling button in S1, it does triggers the service call but while http is in process I can't see loading... text.



Here is code of S1 :



import { Component, OnInit } from '@angular/core';
import { MessagingService } from '../messaging.service';

@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css']
})
export class ParentComponent implements OnInit {

constructor(private _sendMessage: MessagingService) { }

ngOnInit() {
}
notifyChild() {
this._sendMessage.notifySibling();
}
}


Here code of S2 :



import { Component, OnInit,ChangeDetectionStrategy ,ChangeDetectorRef} from '@angular/core';
import { MessagingService } from '../messaging.service';
import { switchMap, takeUntil, delay } from 'rxjs/operators';
import { of } from 'rxjs';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent implements OnInit {
public loading = true;
public myData: any;
constructor(private _receiveMessage: MessagingService,private cd: ChangeDetectorRef) { }

ngOnInit() {
this._receiveMessage.registerNotification().pipe(
switchMap(res => {
this.loading = true;
/** Simulate http call below */
return of([res.data]).pipe(
delay(5000)
)
})
).subscribe(response => {
this.myData = response;
this.loading = false;
this.cd.markForCheck();
})
}

}


Note: I have added this.cd.markForCheck(); in subscription. If i comment this like I am only seeing loading... and no data being displayed



Messaging Service :



import { Injectable } from '@angular/core';
import { Subject, BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class MessagingService {
public _notify = new BehaviorSubject({ data: "initial Call" });
public notify = this._notify.asObservable();
constructor() { }

notifySibling() {
this._notify.next({ data: 'call from sibling' });
}
registerNotification() {
return this.notify;
}

}


Full working example is published on stackblitz










share|improve this question



























    2















    may be I am misunderstanding the changeDetection strategy in angular.



    Here is Description:




    • I have 2 Sibling components (S1 and S2)

    • Think both the components as widget on which some graphical data being displayed

    • When loaded I want to display data on both the component initially. (For this I am using behaviour subject)

    • From S1 I want to notify S2 to trigger a http service call. (I have used behaviour subject and calling .next on click of a button in S1. I am subscribing to same observable in S2 to get the data)

    • My S2 component is registered with onPush change detection strategy.

    • I am using loading text while http service call is in progress and then removing the text after complete using ngIf using primitive variable this.loading=true/false


    Now My problem is when App loads initially I can see loading... text on S2 widget and then data gets populated.



    But when I click on the notify sibling button in S1, it does triggers the service call but while http is in process I can't see loading... text.



    Here is code of S1 :



    import { Component, OnInit } from '@angular/core';
    import { MessagingService } from '../messaging.service';

    @Component({
    selector: 'app-parent',
    templateUrl: './parent.component.html',
    styleUrls: ['./parent.component.css']
    })
    export class ParentComponent implements OnInit {

    constructor(private _sendMessage: MessagingService) { }

    ngOnInit() {
    }
    notifyChild() {
    this._sendMessage.notifySibling();
    }
    }


    Here code of S2 :



    import { Component, OnInit,ChangeDetectionStrategy ,ChangeDetectorRef} from '@angular/core';
    import { MessagingService } from '../messaging.service';
    import { switchMap, takeUntil, delay } from 'rxjs/operators';
    import { of } from 'rxjs';
    @Component({
    selector: 'app-child',
    templateUrl: './child.component.html',
    styleUrls: ['./child.component.css'],
    changeDetection: ChangeDetectionStrategy.OnPush
    })
    export class ChildComponent implements OnInit {
    public loading = true;
    public myData: any;
    constructor(private _receiveMessage: MessagingService,private cd: ChangeDetectorRef) { }

    ngOnInit() {
    this._receiveMessage.registerNotification().pipe(
    switchMap(res => {
    this.loading = true;
    /** Simulate http call below */
    return of([res.data]).pipe(
    delay(5000)
    )
    })
    ).subscribe(response => {
    this.myData = response;
    this.loading = false;
    this.cd.markForCheck();
    })
    }

    }


    Note: I have added this.cd.markForCheck(); in subscription. If i comment this like I am only seeing loading... and no data being displayed



    Messaging Service :



    import { Injectable } from '@angular/core';
    import { Subject, BehaviorSubject } from 'rxjs';
    @Injectable({
    providedIn: 'root'
    })
    export class MessagingService {
    public _notify = new BehaviorSubject({ data: "initial Call" });
    public notify = this._notify.asObservable();
    constructor() { }

    notifySibling() {
    this._notify.next({ data: 'call from sibling' });
    }
    registerNotification() {
    return this.notify;
    }

    }


    Full working example is published on stackblitz










    share|improve this question

























      2












      2








      2








      may be I am misunderstanding the changeDetection strategy in angular.



      Here is Description:




      • I have 2 Sibling components (S1 and S2)

      • Think both the components as widget on which some graphical data being displayed

      • When loaded I want to display data on both the component initially. (For this I am using behaviour subject)

      • From S1 I want to notify S2 to trigger a http service call. (I have used behaviour subject and calling .next on click of a button in S1. I am subscribing to same observable in S2 to get the data)

      • My S2 component is registered with onPush change detection strategy.

      • I am using loading text while http service call is in progress and then removing the text after complete using ngIf using primitive variable this.loading=true/false


      Now My problem is when App loads initially I can see loading... text on S2 widget and then data gets populated.



      But when I click on the notify sibling button in S1, it does triggers the service call but while http is in process I can't see loading... text.



      Here is code of S1 :



      import { Component, OnInit } from '@angular/core';
      import { MessagingService } from '../messaging.service';

      @Component({
      selector: 'app-parent',
      templateUrl: './parent.component.html',
      styleUrls: ['./parent.component.css']
      })
      export class ParentComponent implements OnInit {

      constructor(private _sendMessage: MessagingService) { }

      ngOnInit() {
      }
      notifyChild() {
      this._sendMessage.notifySibling();
      }
      }


      Here code of S2 :



      import { Component, OnInit,ChangeDetectionStrategy ,ChangeDetectorRef} from '@angular/core';
      import { MessagingService } from '../messaging.service';
      import { switchMap, takeUntil, delay } from 'rxjs/operators';
      import { of } from 'rxjs';
      @Component({
      selector: 'app-child',
      templateUrl: './child.component.html',
      styleUrls: ['./child.component.css'],
      changeDetection: ChangeDetectionStrategy.OnPush
      })
      export class ChildComponent implements OnInit {
      public loading = true;
      public myData: any;
      constructor(private _receiveMessage: MessagingService,private cd: ChangeDetectorRef) { }

      ngOnInit() {
      this._receiveMessage.registerNotification().pipe(
      switchMap(res => {
      this.loading = true;
      /** Simulate http call below */
      return of([res.data]).pipe(
      delay(5000)
      )
      })
      ).subscribe(response => {
      this.myData = response;
      this.loading = false;
      this.cd.markForCheck();
      })
      }

      }


      Note: I have added this.cd.markForCheck(); in subscription. If i comment this like I am only seeing loading... and no data being displayed



      Messaging Service :



      import { Injectable } from '@angular/core';
      import { Subject, BehaviorSubject } from 'rxjs';
      @Injectable({
      providedIn: 'root'
      })
      export class MessagingService {
      public _notify = new BehaviorSubject({ data: "initial Call" });
      public notify = this._notify.asObservable();
      constructor() { }

      notifySibling() {
      this._notify.next({ data: 'call from sibling' });
      }
      registerNotification() {
      return this.notify;
      }

      }


      Full working example is published on stackblitz










      share|improve this question














      may be I am misunderstanding the changeDetection strategy in angular.



      Here is Description:




      • I have 2 Sibling components (S1 and S2)

      • Think both the components as widget on which some graphical data being displayed

      • When loaded I want to display data on both the component initially. (For this I am using behaviour subject)

      • From S1 I want to notify S2 to trigger a http service call. (I have used behaviour subject and calling .next on click of a button in S1. I am subscribing to same observable in S2 to get the data)

      • My S2 component is registered with onPush change detection strategy.

      • I am using loading text while http service call is in progress and then removing the text after complete using ngIf using primitive variable this.loading=true/false


      Now My problem is when App loads initially I can see loading... text on S2 widget and then data gets populated.



      But when I click on the notify sibling button in S1, it does triggers the service call but while http is in process I can't see loading... text.



      Here is code of S1 :



      import { Component, OnInit } from '@angular/core';
      import { MessagingService } from '../messaging.service';

      @Component({
      selector: 'app-parent',
      templateUrl: './parent.component.html',
      styleUrls: ['./parent.component.css']
      })
      export class ParentComponent implements OnInit {

      constructor(private _sendMessage: MessagingService) { }

      ngOnInit() {
      }
      notifyChild() {
      this._sendMessage.notifySibling();
      }
      }


      Here code of S2 :



      import { Component, OnInit,ChangeDetectionStrategy ,ChangeDetectorRef} from '@angular/core';
      import { MessagingService } from '../messaging.service';
      import { switchMap, takeUntil, delay } from 'rxjs/operators';
      import { of } from 'rxjs';
      @Component({
      selector: 'app-child',
      templateUrl: './child.component.html',
      styleUrls: ['./child.component.css'],
      changeDetection: ChangeDetectionStrategy.OnPush
      })
      export class ChildComponent implements OnInit {
      public loading = true;
      public myData: any;
      constructor(private _receiveMessage: MessagingService,private cd: ChangeDetectorRef) { }

      ngOnInit() {
      this._receiveMessage.registerNotification().pipe(
      switchMap(res => {
      this.loading = true;
      /** Simulate http call below */
      return of([res.data]).pipe(
      delay(5000)
      )
      })
      ).subscribe(response => {
      this.myData = response;
      this.loading = false;
      this.cd.markForCheck();
      })
      }

      }


      Note: I have added this.cd.markForCheck(); in subscription. If i comment this like I am only seeing loading... and no data being displayed



      Messaging Service :



      import { Injectable } from '@angular/core';
      import { Subject, BehaviorSubject } from 'rxjs';
      @Injectable({
      providedIn: 'root'
      })
      export class MessagingService {
      public _notify = new BehaviorSubject({ data: "initial Call" });
      public notify = this._notify.asObservable();
      constructor() { }

      notifySibling() {
      this._notify.next({ data: 'call from sibling' });
      }
      registerNotification() {
      return this.notify;
      }

      }


      Full working example is published on stackblitz







      angular typescript






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 26 '18 at 7:10









      user1608841user1608841

      1,85111126




      1,85111126
























          1 Answer
          1






          active

          oldest

          votes


















          4














          OnPush strategy run check only when @Input property is changed if you want to run it in async context you have to call this.cd.markForCheck() yourself before request and after request.



          ngOnInit() {
          this._receiveMessage.registerNotification().pipe(
          switchMap(res => {
          this.loading = true;
          /** note this */
          this.cd.markForCheck();
          return of([res.data]).pipe(
          delay(1000)
          )
          })
          ).subscribe(response => {
          this.myData = response;
          this.loading = false;
          this.cd.markForCheck();
          })
          }


          https://stackblitz.com/edit/angular-pmvmgz



          english ain't my native language :(






          share|improve this answer
























          • ok so I believe adding this.cd.markForCheck(); is the only option if i am updating primitive values in async context>

            – user1608841
            Nov 26 '18 at 10:20













          • I tried this and was working previously :) ..just wanted to clear if this is the only solution . I Thought I was doing something wrong.

            – user1608841
            Nov 26 '18 at 10:21













          • i think you could move this request to parent component and pass loading and response to sibling using @Input parameters or just change detectionStrategy to Default

            – karoluS
            Nov 26 '18 at 10:42











          • I guess using this.cd.markForCheck(); is not hack.. even async pipe behind the scene uses markForCheck so its safe to use

            – user1608841
            Nov 26 '18 at 10:47








          • 1





            it is safe as long as you know what you are doing :P

            – karoluS
            Nov 26 '18 at 10:51











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53476204%2fangular-onpush-change-detection-strategy-with-primitive-values%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          4














          OnPush strategy run check only when @Input property is changed if you want to run it in async context you have to call this.cd.markForCheck() yourself before request and after request.



          ngOnInit() {
          this._receiveMessage.registerNotification().pipe(
          switchMap(res => {
          this.loading = true;
          /** note this */
          this.cd.markForCheck();
          return of([res.data]).pipe(
          delay(1000)
          )
          })
          ).subscribe(response => {
          this.myData = response;
          this.loading = false;
          this.cd.markForCheck();
          })
          }


          https://stackblitz.com/edit/angular-pmvmgz



          english ain't my native language :(






          share|improve this answer
























          • ok so I believe adding this.cd.markForCheck(); is the only option if i am updating primitive values in async context>

            – user1608841
            Nov 26 '18 at 10:20













          • I tried this and was working previously :) ..just wanted to clear if this is the only solution . I Thought I was doing something wrong.

            – user1608841
            Nov 26 '18 at 10:21













          • i think you could move this request to parent component and pass loading and response to sibling using @Input parameters or just change detectionStrategy to Default

            – karoluS
            Nov 26 '18 at 10:42











          • I guess using this.cd.markForCheck(); is not hack.. even async pipe behind the scene uses markForCheck so its safe to use

            – user1608841
            Nov 26 '18 at 10:47








          • 1





            it is safe as long as you know what you are doing :P

            – karoluS
            Nov 26 '18 at 10:51
















          4














          OnPush strategy run check only when @Input property is changed if you want to run it in async context you have to call this.cd.markForCheck() yourself before request and after request.



          ngOnInit() {
          this._receiveMessage.registerNotification().pipe(
          switchMap(res => {
          this.loading = true;
          /** note this */
          this.cd.markForCheck();
          return of([res.data]).pipe(
          delay(1000)
          )
          })
          ).subscribe(response => {
          this.myData = response;
          this.loading = false;
          this.cd.markForCheck();
          })
          }


          https://stackblitz.com/edit/angular-pmvmgz



          english ain't my native language :(






          share|improve this answer
























          • ok so I believe adding this.cd.markForCheck(); is the only option if i am updating primitive values in async context>

            – user1608841
            Nov 26 '18 at 10:20













          • I tried this and was working previously :) ..just wanted to clear if this is the only solution . I Thought I was doing something wrong.

            – user1608841
            Nov 26 '18 at 10:21













          • i think you could move this request to parent component and pass loading and response to sibling using @Input parameters or just change detectionStrategy to Default

            – karoluS
            Nov 26 '18 at 10:42











          • I guess using this.cd.markForCheck(); is not hack.. even async pipe behind the scene uses markForCheck so its safe to use

            – user1608841
            Nov 26 '18 at 10:47








          • 1





            it is safe as long as you know what you are doing :P

            – karoluS
            Nov 26 '18 at 10:51














          4












          4








          4







          OnPush strategy run check only when @Input property is changed if you want to run it in async context you have to call this.cd.markForCheck() yourself before request and after request.



          ngOnInit() {
          this._receiveMessage.registerNotification().pipe(
          switchMap(res => {
          this.loading = true;
          /** note this */
          this.cd.markForCheck();
          return of([res.data]).pipe(
          delay(1000)
          )
          })
          ).subscribe(response => {
          this.myData = response;
          this.loading = false;
          this.cd.markForCheck();
          })
          }


          https://stackblitz.com/edit/angular-pmvmgz



          english ain't my native language :(






          share|improve this answer













          OnPush strategy run check only when @Input property is changed if you want to run it in async context you have to call this.cd.markForCheck() yourself before request and after request.



          ngOnInit() {
          this._receiveMessage.registerNotification().pipe(
          switchMap(res => {
          this.loading = true;
          /** note this */
          this.cd.markForCheck();
          return of([res.data]).pipe(
          delay(1000)
          )
          })
          ).subscribe(response => {
          this.myData = response;
          this.loading = false;
          this.cd.markForCheck();
          })
          }


          https://stackblitz.com/edit/angular-pmvmgz



          english ain't my native language :(







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 26 '18 at 7:45









          karoluSkaroluS

          618213




          618213













          • ok so I believe adding this.cd.markForCheck(); is the only option if i am updating primitive values in async context>

            – user1608841
            Nov 26 '18 at 10:20













          • I tried this and was working previously :) ..just wanted to clear if this is the only solution . I Thought I was doing something wrong.

            – user1608841
            Nov 26 '18 at 10:21













          • i think you could move this request to parent component and pass loading and response to sibling using @Input parameters or just change detectionStrategy to Default

            – karoluS
            Nov 26 '18 at 10:42











          • I guess using this.cd.markForCheck(); is not hack.. even async pipe behind the scene uses markForCheck so its safe to use

            – user1608841
            Nov 26 '18 at 10:47








          • 1





            it is safe as long as you know what you are doing :P

            – karoluS
            Nov 26 '18 at 10:51



















          • ok so I believe adding this.cd.markForCheck(); is the only option if i am updating primitive values in async context>

            – user1608841
            Nov 26 '18 at 10:20













          • I tried this and was working previously :) ..just wanted to clear if this is the only solution . I Thought I was doing something wrong.

            – user1608841
            Nov 26 '18 at 10:21













          • i think you could move this request to parent component and pass loading and response to sibling using @Input parameters or just change detectionStrategy to Default

            – karoluS
            Nov 26 '18 at 10:42











          • I guess using this.cd.markForCheck(); is not hack.. even async pipe behind the scene uses markForCheck so its safe to use

            – user1608841
            Nov 26 '18 at 10:47








          • 1





            it is safe as long as you know what you are doing :P

            – karoluS
            Nov 26 '18 at 10:51

















          ok so I believe adding this.cd.markForCheck(); is the only option if i am updating primitive values in async context>

          – user1608841
          Nov 26 '18 at 10:20







          ok so I believe adding this.cd.markForCheck(); is the only option if i am updating primitive values in async context>

          – user1608841
          Nov 26 '18 at 10:20















          I tried this and was working previously :) ..just wanted to clear if this is the only solution . I Thought I was doing something wrong.

          – user1608841
          Nov 26 '18 at 10:21







          I tried this and was working previously :) ..just wanted to clear if this is the only solution . I Thought I was doing something wrong.

          – user1608841
          Nov 26 '18 at 10:21















          i think you could move this request to parent component and pass loading and response to sibling using @Input parameters or just change detectionStrategy to Default

          – karoluS
          Nov 26 '18 at 10:42





          i think you could move this request to parent component and pass loading and response to sibling using @Input parameters or just change detectionStrategy to Default

          – karoluS
          Nov 26 '18 at 10:42













          I guess using this.cd.markForCheck(); is not hack.. even async pipe behind the scene uses markForCheck so its safe to use

          – user1608841
          Nov 26 '18 at 10:47







          I guess using this.cd.markForCheck(); is not hack.. even async pipe behind the scene uses markForCheck so its safe to use

          – user1608841
          Nov 26 '18 at 10:47






          1




          1





          it is safe as long as you know what you are doing :P

          – karoluS
          Nov 26 '18 at 10:51





          it is safe as long as you know what you are doing :P

          – karoluS
          Nov 26 '18 at 10:51


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53476204%2fangular-onpush-change-detection-strategy-with-primitive-values%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

          Calculate evaluation metrics using cross_val_predict sklearn

          Insert data from modal to MySQL (multiple modal on website)