How to "refresh" *ngIf?

After i click to play or pause button it is working properly, but when i change the isPlaying variable from an event listener, then the *ngIf is not working, how can i refresh it (without full page refresh or anything like that)?

The html:

  <button ion-button (click)="play()" *ngIf="!isPlaying" color="green-button" icon-only clear>
    <ion-icon name="play"></ion-icon>
  </button>

  <button ion-button (click)="play()" *ngIf="isPlaying" color="red-button" icon-only clear>
    <ion-icon name="pause"></ion-icon>
  </button>

The .ts file:

this.wavesurfer.on('finish', function() {
  this.isPlaying = false;
}.bind(this));

The on function is changing the value to false.

Any help would be appreciated.

I think the problem is that the this from wavesurfer finish event is not the component itself but the wavesurfer object (or the event function itself)

Try to debug the this like:

this.wavesurfer.on('finish', function() {
    console.log(this);
    this.isPlaying = false;
}.bind(this));

And see if it is the component itself.

If not, one solution can be to set a variable _self = this outside the on finish event and change the event function to _self.isPlaying = false;

The .bind(this) do the trick, as i mentioned it is working. The variable will be false, but the icon stay on pause.
*ngIf needs a refresh, but i do not know (forgot) how. I think the problem that the *ngIf has not been called after an on event.

I read that the *ngIf create a new scope, so maybe it can be the problem, but i do not know how to use $parent in Ionic 2.

However, thanks, do you know how to use $parent maybe? :slight_smile:

This is probably what you want. It’s solved a lot of problems for me.

https://angular.io/docs/ts/latest/api/core/index/ChangeDetectorRef-class.html#!#detectChanges-anchor

Try this instead

this.wavesurfer.on('finish', () => {
  this.isPlaying = false;
});

*ngIf checks for changes on it’s own, you don’t need to do anything. I’m pretty confident it’s just a this issue

An arrow function expression has a shorter syntax than a function expression and does not bind its own this, arguments, super, or new.target. These function expressions are best suited for non-method functions, and they cannot be used as constructors.

##Basic Syntax

(param1, param2, ..., paramN) => { statements }
(param1, param2, ..., paramN) => expression
// equivalent to: (param1, param2, ..., paramN) => { return expression; }

// Parentheses are optional when there's only one parameter:
(singleParam) => { statements }
singleParam => { statements }

// A function with no parameters requires parentheses:
() => { statements }
() => expression // equivalent to: () => { return expression; }

- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

Thanks, i tried this and still not working, because it is equivalent to the .bind().
(However i had to search a lot when i had this problem, i was happy when i found the .bind() function, but which you mentioned, that is better, and i will use it.)

IMHO the cleanest way to do this is to make a shim for this library in a provider that does roughly this:

class WaveSurfer {
  whenFinished(): Promise<void> {
    return new Promise((resolve) => {
      this.wavesurfer.on('finish', () => resolve());
    });
  }
}
class Page {
  isPlaying: boolean;

  constructor(private _surfer: WaveSurfer) {
    _surfer.whenFinished().then(() => this.isPlaying = false);
  }
}