8

In my app.component.ts I am making an API call and fetching userDetails. I am then emitting this userDetails. I have subscribed to this userDetails in my header component. My header component uses app-my-image-logo component. On page refresh, API is called and userDetails are fetched. After that, event is emitted and therefore, testnDisplay method is called. But my problem is every few seconds, I get the following output on my console.

img   my-image-logo.component.ts:28
name  my-image-logo.component.ts:28
img   my-image-logo.component.ts:28
name  my-image-logo.component.ts:28
img   my-image-logo.component.ts:28
name  my-image-logo.component.ts:28
img   my-image-logo.component.ts:28
name  my-image-logo.component.ts:28

So, this method is getting called multiple times after frequent intervals but it should have been called only once.

header.component.html

<app-my-image-logo ></app-my-image-logo>

header.component.ts

ngOnInit() {
        const self = this;
        this.userDetails = this.dataService.getUserDetails();
        this.dataService.userDetailsEvt.subscribe(
            function(data){
                self.userDetails = data;
            }
        );

    }

This is app-my-logo component.

app-logo.component.html

<img #imgDiv  [hidden]="testnDisplay('img')" >

<div [hidden]="testnDisplay('name')"
     ></div>

app-logo.component.ts

testnDisplay(type){
        console.log(type);
}

This is my dataService:

data.service.ts

setUserDetails(userDetails){
        this.userDetails = userDetails;
        this.userDetailsEvt.emit(this.userDetails);
    }

    getUserDetails(){
        return this.userDetails;
    }

app.component.ts

this.authService.httpPost("/auth/getUserDetails", payload).subscribe(
            function (data: any) {
                self.dataService.setUserDetails(data);
            },
            function(error){

            }
        );
helloworld
  • 1,002
  • 3
  • 15
  • 27

1 Answers1

18

This is because you are using the Default change detection strategy on your component. By default all components use this strategy which means that when Angular determines a component's state is dirty it re-renders the template and cause the testnDisplay function to be called. In order to remove the component from default checking you should set the strategy to OnPush which is much more perfomant because it only re-renders the template when one of the @Input properties changes. It is still possible to have the template re-rendered but it requires the component to tell angular when to do so. Example:

@Component({
  /* ... */
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppLogoComponent  {
  testnDisplay(type){
    console.log(type);
  }
}
Teddy Sterne
  • 13,774
  • 2
  • 46
  • 51
  • Thanks Teddy, this is working but I am still confused. Why would `Default` category treat the component's state as dirty when no value is getting changed? `EventEmitter` is only changing the value once, so it should be called only once. – helloworld Nov 12 '18 at 18:05
  • 1
    The default behavior says to re-render whenever Angular thinks that something could have changed. Angular thinks something might have changed after an event is fired, an XHR occurs, or a timer fires (basically all async actions). It uses zones to determine what components could be affected and then tells those to re-render. https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html – Teddy Sterne Nov 12 '18 at 18:19