Reputation: 29
I am trying to make a music-app, so what I want to do is when the current music ends, it will automatically plays the next song in line, but what happens is, the EventListener get triggered by times 2, firstly it is triggered one time, and then 2 time, and then 4, and the number keeps increasing every time the EventListener gets triggered, I've tried searching for solutions in other websites but I just can't seem to find the answer, hope anyone can help
By the way I am using vue js
these are my data
data () {
return {
current: {},
index: 0,
isPlaying: false,
api_key: '4f40bf40b2msh6d957020229b6c6p1fe925jsn4ef16ee46284',
url_base: 'https://deezerdevs-deezer.p.rapidapi.com',
songs: [],
query:'',
player: new Audio()
}
},
and this is my method for playing the music
play (song) {
if (typeof song.title != "undefined") {
this.current = song;
this.player.src = this.current.preview;
}
this.player.play();
//console.log(this.player);
this.player.addEventListener('ended', function () {
console.log(this.index);
//this.index++;
if (this.index > this.songs.length - 1) {
this.index = 0;
}
this.current = this.songs[this.index];
this.play(this.current);
}.bind(this));
this.isPlaying = true;
},
if anyone has better suggestion for me to make this will also be a huge favour
Upvotes: 0
Views: 626
Reputation: 19376
The symptoms are caused by adding the event listener multiple times without removing it. Solutions include
adding the event listener once, outside the operational loop of play()
, raising an ended
event, handling the ended
event, and calling play
again (from within the listener).
removing the previous event handler, if one was added, from within the ended
handler before adding a new handler. Not recommended because of the additional complexity of maintaining a reference to the function returned by bind
in order to remove it later.
have the browser remove the handler for you after calling it, by including {once: true}
as the third argument of addEventListener
when adding the event handler:
this.player.addEventListener('ended', function () {
// handler to play once, loop, loop to end, shuffle or whatever
}.bind(this), {once: true});
Check the browser compatibility section of the MDN documentation however - using the option effectively means dropping for support for IE.
Upvotes: 1
Reputation: 22623
The problem is that each time your play method gets called, a new event listener gets added. Then, whenever a song ends, all of the previously added listeners get called.
(You seem to be under the impression that the listener gets retired after being called. This is not the case; they stick around until you remove them.)
You should move the addEventListener call from out of your play method, and put it somewhere else. E.g. you could do it in the constructor of your class, or in the outer-most scope.
Upvotes: 1