1

I want to pause the playing audio if another one is played. I have this

            <ul class="music-list">

                <li *ngFor="let song of Songs">
                    <div class="music-panel">
                        <div class="music-image">
                            <img src="{{ song.song_image }}" alt="music-img">
                        </div>
                        <div class="music-detail">
                            <span class="date-remind">Season 1 / 10 September 2018</span>
                            <h4>{{ song.song_title | titlecase }}</h4>
                            <div class="music-play">
                                <audio controls>
                                    <source src="{{ song.audio_file }}" type="audio/mpeg">
                                </audio>
                            </div>
                        </div>
                    </div>
                </li>
            </ul>

Please help. Thanks

3 Answers 3

2

you need to get a reference of all element in the view then loop throw them an run pause method

@ViewChildren('audio') audioElms :ElementRef[];

now on the template bind a method on the audio play event

<audio controls #audio (play)="paly(audio)">
     <source src="{{ song.audio_file }}" type="audio/mpeg">
 </audio>

the play method will loop throw the audio elment and pause

onPaly(elm:HTMLAudioElement) {
  this.audioElms.forEach(({nativeElement:e})=>{
   if (e !== elm) {
     e.pause();
   }
  })
}

check the complete demo 👉 demo 👓

Updated for better performance 🔥🔥

in case we have many elementd keep loop through theme everytime for just pause one of is a low preformance way.

simply we will save a reference of the current played audio element and stop when we play another one

  private currentPlayedElem: HTMLAudioElement = null;

  onPaly(elm: HTMLAudioElement) {
    if (this.currentPlayedElem && this.currentPlayedElem !== elm ) {
      this.currentPlayedElem.pause();
    }

    this.currentPlayedElem = elm;
  }

demo 🎉

Sign up to request clarification or add additional context in comments.

2 Comments

If you have 100+ audio files in a view, why would you loop through all of them if you only need to pause one and play another one?
@FrisoHoekstra thanks for mention this problem I have update my answer will very simple way
1

You could omit the <audio> element from your template and move the player logic to a service:

export class AudioPlayerService {    
    private globalPlayer: HTMLMediaElement = new Audio();    
}

UPDATE Demo: https://angular-eg8uik.stackblitz.io/

You can keep track of the player's state using addEventListener(). Pass it to an Observable stream and use it in your component.

private playerState = new BehaviorSubject<any>({ isPlaying: false });

constructor() {
    this.globalPlayer.addEventListener('play', () => {
        this.playerState.next({ isPlaying: true, audioId: 'foo' });
    });

    this.globalPlayer.addEventListener('pause', () => {
        this.playerState.next({ isPlaying: false });
    });
}

getState(): Observable<any> {
    return this.playerState.asObservable();
}

Pass getState() to your custom audio player component and update the buttons accordingly.

You can also add functions for loading, playing, pausing, stopping, seeking, currentTime values, etc.

This will scale well because you have only one MediaElement and two EventListeners no matter how many files you have in your view. You are also more flexible with your UI, the native <audio> element is pretty limited as far as design goes.

1 Comment

I like your way and already voted , but can you provide a demo , you can fork one of my answer , this will be very helpful for others 👍
0

Add listener to the play event in the capturing phase and pause all audio file except the target one:

    document.addEventListener('play', function(e){
        var audios = document.getElementsByTagName('audio');
        for(var i = 0, len = audios.length; i < len;i++){
            if(audios[i] != e.target){
                audios[i].pause();
            }
        }
    }, true);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.