1

I'm trying to build a small audio player but can't seem to get nice change detection, for example for the audio track current time. For example, I have the track playing fine in my component and in my template file I have

{{ player.currentTime }}

But the time only seems to be updated when I perform other events such as clicking around or play/pause button for example. It doesn't intuitively update live as the track is playing. Seems like issue with change detection or something?

For working example, see ngx-admin-demo (https://akveo.com/ngx-admin/#/pages/iot-dashboard) and scroll down slightly to see the player. If you press play and stop moving mouse you will see what I mean, it doesn't update progress bar or time unless you are performing action.

NJ.
  • 7,486
  • 1
  • 19
  • 20

1 Answers1

0

Try something like this in your component to encourage change detection every second without the user having to perform some event to spur a change detection (Angular2+ only performs change detection on XHR requests, events and setTimeout/setInterval):

@Component({
  selector: 'my-player',
  changeDetection: ChangeDetectionStrategy.OnPush,
  templateUrl: '/path/to/my-player.template.html'
})
class MyPlayer {
  constructor(private ref: ChangeDetectorRef) {
    setInterval(() => {
      this.ref.markForCheck();
    }, 1000);
  }
}
Sean Murphy
  • 516
  • 4
  • 7
  • Hi Sean, that works great for things like the current time, but what about progress bar, it looks rather jerky having it jump every one second. Would I simply lower the interval timer? Do you think this will become inefficient in the long run? – NJ. Jan 03 '19 at 23:21
  • Yeah - there is definitely a cost for this kind of change detection. You can lower the interval down to perhaps 250ms or 100ms in order to to make it a bit smoother. The finer your granularity, the more it will impact performance. I'm not sure what the specific use-case is for your component, but if it's not something that's visible at all times, the performance hit may be worth the improved user experience. – Sean Murphy Jan 03 '19 at 23:30
  • Thanks, I'm using this to place an audio player visible in the footer of the site most of the time if not all of the time, so it's pretty important. Do you know if this is expected behaviour? Am I missing something else that would make this work as I envisioned? I was thinking of creating an observable of the current time somehow and using async pipe, would that be better? – NJ. Jan 03 '19 at 23:33
  • Yeah - this is expected behavior. The Observable pattern would work - but you have to have some kind of eventing firing from the player in order to pass the current play time to the Subject of your Observable. You may run into the same kind of performance vs. granularity of event firing issue here as well. If you go the setInterval route, it might be worth tracking the interval ID returned by setInterval, and then calling clearInterval on that ID in an ngOnDestroy() function....just to clean up. – Sean Murphy Jan 03 '19 at 23:35