Home > OS >  Instance variables in Angular component are not working from within a setInterval called function
Instance variables in Angular component are not working from within a setInterval called function

Time:08-04

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

  • Related