My Angular 13 component should show a progress bar while an audio file is being played.
I'm trying to increase the progress bar value (runs from 0 to 1) by a calculated interval in a function called with setInterval() to run every 1/100th of a second.
The called function is: progressTimeBar().
progressTimeBar(interval: number) {
this.p_bar_value = Number(this.p_bar_value interval);
console.log('Advanced p_bar_value: ', interval, this.p_bar_value);
}
The p_bar_value instance variable of the component is NOT accessible correctly from within progressTimeBar. The console log renders it as NaN (that's why I tried to to force the Number() on its calculation - to no avail. Always NaN). Console:
Advanced p_bar_value: 0.002 NaN
Btw, the there is an instance variable called interval as well, but accessing it directly in this function using this.interval yields the same results - NaN. That's why I am now passing it as an argument. But I must advance the instance p_bar_value as it is bound to the template value of the progress bar!
Here's the component:
import { Component, Input } from '@angular/core';
import { VoiceService } from "../../services/voice.service";
import { StreamState } from "../../Utilities/stream-state";
@Component({
selector: 'app-audioplayer',
templateUrl: './audioplayer.component.html',
styleUrls: ['./audioplayer.component.scss'],
providers: [VoiceService]
})
export class AudioplayerComponent {
@Input() url: string;
audioDurationDisplay: string;
state: StreamState;
p_bar_value: number = 0;
totalDuration: number = 0;
playingNow: boolean;
timerHandle: any;
interval: number = 0;
loaded: boolean = false;
constructor(public audioService: VoiceService) {
// listen to stream state
this.audioService.getState().subscribe(state => {
this.state = state;
console.log('StreamState in Audioplayer updated: ', this.state);
if (this.state.duration) {
this.totalDuration = this.state.duration;
this.interval = 0.01 / this.totalDuration;
console.log('Updated TotalDuration from state: ', this.totalDuration);
}
if (this.state.ended) {
clearInterval(this.timerHandle);
this.p_bar_value = 0;
}
});
}
ngOnChanges() {
if(this.url) {
console.log('this.url received: ', this.url);
this.CalcTotalDuration();
this.loaded = true;
}
}
CalcTotalDuration() {
const durationRaw = this.url.slice(this.url.lastIndexOf(".")-4, this.url.lastIndexOf("."));
this.audioDurationDisplay = durationRaw.slice(0, 1) ":" durationRaw.slice(-2);
const arrRaw = this.audioDurationDisplay.split(":");
this.totalDuration = (parseInt(arrRaw[0]) * 60) (parseInt(arrRaw[1])); //Total in seconds
this.interval = 0.01 / this.totalDuration;
console.log('Calculated TotalDuration: ', this.totalDuration);
}
playController() {
console.log('Calling progressTimeBar. totalDuration: ', this.totalDuration, Number.isNaN(this.totalDuration));
console.log('Calling progressTimeBar. interval: ', this.interval, Number.isNaN(this.interval));
console.log('Calling progressTimeBar. p_bar_value: ', this.p_bar_value, Number.isNaN(this.p_bar_value));
clearInterval(this.timerHandle);
this.timerHandle = setInterval(this.progressTimeBar, 10, this.interval);
if (this.state.canplay) {
this.play();
} else {
this.playStream();
}
}
playStream() {
this.audioService.playStream(this.url).subscribe(events => {
this.playingNow = true;
});
}
pause() {
this.audioService.pause();
clearInterval(this.timerHandle);
this.playingNow = false;
}
//Restart playing again (resume after pause)
play() {
this.audioService.play();
this.playingNow = true;
}
stop() {
this.audioService.stop();
clearInterval(this.timerHandle);
this.playingNow = false;
this.p_bar_value = 0;
}
progressTimeBar(interval: number) {
this.p_bar_value = Number(this.p_bar_value interval);
console.log('Advanced p_bar_value: ', interval, this.p_bar_value);
}
ngOnDestroy() {
clearInterval(this.timerHandle);
}
}
What am I missing?
CodePudding user response:
Could you try declaring progressTimeBar
as an arrow function? We are using it as a callback and we lose this
scope.
Either
this.timerHandle = setInterval((interval) => { this.p_bar_value = interval }, 10, this.interval);
or
const progressTimeBar = (interval: number) => {
this.p_bar_value = Number(this.p_bar_value interval);
}
this.timerHandle = setInterval(progressTimeBar, 10, this.interval);
should work