title: Change detection running infinitely when function is used with ngIf
body: <p>I am working on an Ionic 2 project. The template has a ngIf to check if its the right user.</p>
  
  <p><code>show.ts</code></p>
  
  <pre><code>  constructor( public book: Bookemon ){}
    rightUser(){
      console.log('right user');
      return this.book.rightUser(this.hunt.user.id);
    }
  </code></pre>
  
  <p><code>bookemon.ts</code> (<code>bookemon</code> and <code>auth</code> are services )</p>
  
  <pre><code>  rightUser(id: number){
      return this.auth.user.id === id;
    }
  </code></pre>
  
  <p><code>show.html</code></p>
  
  <pre><code>&lt;ion-content  fullscreen="true"&gt;
    &lt;div id="image-modal" &gt;
      &lt;img [src]="imageSource(hunt.picture_url)" (click)="dismissModal()" &gt;
      &lt;button ion-fab mini *ngIf = " !hunt.picture_url " (click)="showEditHuntModal()" color="ionic"&gt;
        &lt;ion-icon  name="add" &gt;&lt;/ion-icon&gt;
      &lt;/button&gt;
      &lt;button color="danger" class="new-claim" ion-button round icon-left *ngIf = "rightUser() &amp;&amp; hunt.claims.length " (click)="openClaimModal(hunt)"&gt;
        &lt;ion-icon name="trophy"&gt;&lt;/ion-icon&gt;
        New Claim
      &lt;/button&gt;
    &lt;/div&gt;
    &lt;div class="hunt-content"&gt;
      &lt;button small clear ion-button icon-only class="options" *ngIf="rightUser()" (click)="presentAction()"&gt;
        &lt;ion-icon name="md-more"&gt;&lt;/ion-icon&gt;
      &lt;/button&gt;
      &lt;hunt [hunt]="hunt" [huntedUser]="huntedUser" &gt;&lt;/hunt&gt;
    &lt;/div&gt;
    &lt;ion-fab *ngIf="hunt.dfu !== undefined" bottom (click)="dismissModal('rejected')"   class="close-fab"&gt;
      &lt;button ion-fab   color="danger" &gt;&lt;ion-icon  name="close" &gt;&lt;/ion-icon&gt;&lt;/button&gt;
    &lt;/ion-fab&gt;
    &lt;ion-fab *ngIf="hunt.dfu !== undefined" bottom (click)="dismissModal('accepted')"  class="heart-fab"&gt;
      &lt;button ion-fab  color="primary"    &gt;&lt;ion-icon  name="heart" &gt;&lt;/ion-icon&gt;&lt;/button&gt;
    &lt;/ion-fab&gt;
  &lt;/ion-content&gt;
  </code></pre>
  
  <p>The template displays some content based on <code>*ngIf = "rightUser()"</code></p>
  
  <p>Everything works fine except , the console is logged with <strong>infinitely many</strong> <code>right user</code> which comes from <code>rightUser()</code> function. The expected behaviour should be <code>right user</code> logged once in console and no more change detection being run.</p>
  
  <p>Is it a bad practice to use functions in <code>ngIf</code> ? What is triggering change detection infinite times  here?</p>
  
  <p><strong>Edit</strong></p>
  
  <p>I tried a function with <code>ngIf</code> in a fresh project and it doesnt run change detection infinite times. I am not sure whats causing it here. Here is my <code>show.ts</code> in case that helps.</p>
  
  <pre><code>export class ShowPage {
    hunt: Hunt ;
    huntedUser: User;
    editHuntPage= EditHuntPage;
    claimHuntPage = ClaimHuntPage;
    rightUser: Boolean;
    constructor(public alert: AlertController , public modal: ModalController, public events: Events
      , public toastCtrl: ToastController, private navParams: NavParams , public action: ActionSheetController
      , public book: Bookemon , public viewCtrl: ViewController, public nav: NavController) {
      console.log(navParams.data);
      this.hunt = navParams.data.hunt;
      this.rightUser = this.book.rightUser(this.hunt.id);
    }
    ionViewDidLoad(){
      console.log('view');
      if(this.hunt.status == "hunted"){
        this .book.getHuntedUser(this.hunt).subscribe( (res) =&gt; {
          this.huntedUser = res.json();
          console.log(this.huntedUser);
        })
      }
    }
    imageSource(pic: string){
      return pic ? pic : CONFIG.noHuntPic ;
    }
    dismissModal(status?: string){
      console.log('dismiss');
      this.viewCtrl.dismiss(status);
    }
    presentAction(){
      let actionSheet = this.action.create(
      {
        title: this.hunt.title ,
        buttons: [
        {
          text: 'Edit',
          handler: () =&gt; {
            let trans = actionSheet.dismiss();
            trans.then( () =&gt; {
              this.showEditHuntModal();
            })
            return false;
          }
        },
        {
          text: 'Delete',
          role: 'destructive',
          handler: () =&gt; {
            let trans = actionSheet.dismiss();
            trans.then( () =&gt; {
              this.deleteAlert();
            })
            return false;
          }
        },
        {
          text: 'Cancel',
          role: 'cancel',
        }
        ]
      })
      actionSheet.present();
    }
    showEditHuntModal(){
      let modal = this.modal.create(EditHuntPage,this.hunt);
      modal.present();
      modal.onDidDismiss( (data) =&gt; {
        if(data){
          this.hunt = data;
        }
      })
    }
    deleteAlert(){
      let alert = this.alert.create({
        title: 'Confirm',
        message: 'Do you want to delete this hunt?',
        buttons: [{
          text: "Delete",
          handler: () =&gt; { this.deleteHunt() }
        }, {
          text: "Cancel",
          role: 'cancel'
        }]
      })
      alert.present();
    }
    deleteHunt(){
      this.book.deleteHunt(this.hunt.id).subscribe( (res) =&gt; {
        // this.events.publish("user-hunts:deleted",this.hunt);
        this.viewCtrl.dismiss("deleted",this.hunt);
      }, (err) =&gt; {
        this.handleError(err);
      })
    }
    openClaimModal(hunt){
      let claimModal =  this.modal.create(ShowClaimPage,{hunt: hunt})
      claimModal.present();
    }
     rightUser(){
       console.log('right user');
       return this.book.rightUser(this.hunt.user.id);
    }
    handleError(err){
      console.log(err);
      let error= err.message ? err.message : "Error occured";
      let toast = this.toastCtrl.create({ message: error, duration: 2000 , position: 'top'});
      toast.present();
    }
  
  }
  </code></pre>