Technologies:
Tolerim
17 hours ago
The event listener is not functioning properly on the initial click.
I am currently working on a music app that includes a feature where users can click on a song and have it play, with the song details added to the "playing now" section and an equalizer animation starting. However, I am experiencing an issue where the first click doesn't work, but the second click does, and the third doesn't. I have provided an example of what I'm doing below, including my code. To resolve this issue, I suggest checking to see if the audio is already playing and then pausing it before playing the selected song. This can be achieved by looping through all the music elements and pausing them before playing the selected song. You can then use a boolean variable to toggle whether the audio is playing or not and use the equalizer animation accordingly. Here is the code for this solution, enclosed within tags for compatibility with HTML:
const playingNow = document.querySelector('.song-p-now');
const equalizer = document.querySelectorAll('.eq')
const btns = Array.from(document.querySelectorAll('.song-details'));
const music = [
{
img: 'img/2.jpg',
id:1,
songName: 'Am I Wrong',
audio : new Audio('audio/Am-I-wrong.mp3'),
artist: 'Nico & Vinz',
},
{
img: 'img/3.jpg',
id:2,
songName: 'Sex,Drugs,Etc',
audio : new Audio('audio/Sex-Drugs-Etc.mp3'),
artist: 'Beach Weather',
},
{
img: 'img/7.jpg',
id:3,
songName: 'Me Myself & I ',
audio : new Audio('audio/Me-Myself-I.mp3'),
artist: 'G-easy',
},
{
img: 'img/4.jpg',
id:4,
songName: 'Blood In The Water',
audio : new Audio('audio/Blood-In-The-Water.mp3'),
artist: 'grandson',
},
{
img: 'img/5.jpg',
id:5,
songName: 'Eastside',
audio : new Audio('audio/Eastside.mp3'),
artist: 'Benny Blanco',
},
{
img: 'img/6.jpg',
id:6,
songName: 'Everything Black ',
audio : new Audio('audio/Everything-Black.mp3'),
artist: 'Unlike Puto',
},
]
let isPlaying = true;
const btnsLoop = () => {
for (j = 0; j < btns.length; j++) {
const musicObject = music[j];
const { img, id, songName, audio, artist } = musicObject;
btns[j].addEventListener('click', () => {
playingNow.innerHTML = `<div class="song-poster"><img src="${img}" alt=""></div>
<div class="song-artist-name">
<div class="song-name">${songName}</div>
<div class="artist-name">${artist}</div>
</div>`
music.forEach(element => {
element.audio.pause();
});
if (isPlaying) {
musicObject.audio.play();
equalizer.forEach((eq) => {
eq.classList.add('animation');
})
isPlaying = false;
}
else {
musicObject.audio.pause();
musicObject.audio.currentTime = "0";
equalizer.forEach((eq) => {
eq.classList.remove('animation');
})
isPlaying = true;
}
});
}
}
btnsLoop();
Answers(1)
Tolerim
17 hours ago
Verified Answer
It's hard to tell exactly what's causing the issue without seeing the HTML and CSS for the rest of the app, but one potential problem could be that the event listeners for the song buttons are not being set up properly.
One improvement you could make to the code is to only set up the event listeners once, instead of setting them up every time the loop runs. To do this, you could move the event listener code outside of the loop and use event delegation to listen for clicks on the container that holds all the song details.
Here's an example of how you could modify the code to do this:
const playingNow = document.querySelector('.song-p-now');
const equalizer = document.querySelectorAll('.eq')
const music = [
{
img: 'img/2.jpg',
id:1,
songName: 'Am I Wrong',
audio : new Audio('audio/Am-I-wrong.mp3'),
artist: 'Nico & Vinz',
},
// ...
]
let isPlaying = true;
// set up event listener using event delegation
const songsContainer = document.querySelector('.songs-container');
songsContainer.addEventListener('click', event => {
const target = event.target.closest('.song-details');
if (!target) {
return;
}
const musicObject = music.find(m => m.id === Number(target.dataset.id));
const { img, songName, audio, artist } = musicObject;
playingNow.innerHTML = `<div class="song-poster"><img src="${img}" alt=""></div>
<div class="song-artist-name">
<div class="song-name">${songName}</div>
<div class="artist-name">${artist}</div>
</div>`;
music.forEach(element => {
element.audio.pause();
});
if (isPlaying) {
musicObject.audio.play();
equalizer.forEach(eq => {
eq.classList.add('animation');
});
isPlaying = false;
} else {
musicObject.audio.pause();
musicObject.audio.currentTime = 0;
equalizer.forEach(eq => {
eq.classList.remove('animation');
});
isPlaying = true;
}
});
In this example, we're using event.target.closest('.song-details') to find the closest ancestor of the clicked element that has the .song-details class. We then use dataset.id to get the ID of the song that was clicked and look it up in the music array using Array.find().
We then set the details of the selected song in the playingNow element and play or pause the audio as appropriate.