Add another track for custom Audio Player

I have JavaScript code, there is problem that I can’t add another tracks and the player is not working

I have changed querySelector to querySelectorAll <<< still is not working!

const audioPlayer = document.querySelector(".audio-player");

console.dir(audio);

audio.addEventListener(
  "loadeddata",
  () => {
    audioPlayer.querySelector(".time .length").textContent = getTimeCodeFromNum(
      audio.duration
    );
    audio.volume = 1.0;
  },
  false
);


//click on timeline to skip around
const timeline = audioPlayer.querySelector(".timeline");
timeline.addEventListener("click", e => {
  const timelineWidth = window.getComputedStyle(timeline).width;
  const timeToSeek = e.offsetX / parseInt(timelineWidth) * audio.duration;
  audio.currentTime = timeToSeek;
}, false);

//click volume slider to change volume
const volumeSlider = audioPlayer.querySelector(".controls .volume-slider");
volumeSlider.addEventListener('click', e => {
  const sliderWidth = window.getComputedStyle(volumeSlider).width;
  const newVolume = e.offsetX / parseInt(sliderWidth);
  audio.volume = newVolume;
  audioPlayer.querySelector(".controls .volume-percentage").style.width = newVolume * 100 + '%';
}, false)

//check audio percentage and update time accordingly
setInterval(() => {
  const progressBar = audioPlayer.querySelector(".progress");
  progressBar.style.width = audio.currentTime / audio.duration * 100 + "%";
  audioPlayer.querySelector(".time .current").textContent = getTimeCodeFromNum(
    audio.currentTime
  );
}, 500);

//toggle between playing and pausing on button click
const playBtn = audioPlayer.querySelector(".controls .toggle-play");
playBtn.addEventListener(
  "click",
  () => {
    if (audio.paused) {
      playBtn.classList.remove("fa-play");
      playBtn.classList.add("fa-pause-circle");
      audio.play();
    } else {
      playBtn.classList.remove("fa-pause");
      playBtn.classList.add("fa-play");
      audio.pause();
    }
  },
  false
);

audioPlayer.querySelector(".volume-button").addEventListener("click", () => {
  const volumeEl = audioPlayer.querySelector(".volume-container .volume");
  audio.muted = !audio.muted;
  if (audio.muted) {
    volumeEl.classList.remove(".volume");
    volumeEl.classList.add("pause");
  } else {
    volumeEl.classList.add(".volume");
    volumeEl.classList.remove("pause");
  }
});

//turn 128 seconds into 2:08
function getTimeCodeFromNum(num) {
  let seconds = parseInt(num);
  let minutes = parseInt(seconds / 60);
  seconds -= minutes * 60;
  const hours = parseInt(minutes / 60);
  minutes -= hours * 60;

  if (hours === 0) return `${minutes}:${String(seconds % 60).padStart(2, 0)}`;
  return `${String(hours).padStart(2, 0)}:${minutes}:${String(
    seconds % 60
  ).padStart(2, 0)}`;
}


 //new function for speed audio	
 var speedlist = document.getElementById("speedlist");
 speedlist.addEventListener("change",changeSpeed);
 
   function changeSpeed(event){
   audio.playbackRate = event.target.value;
 }

Please post the HTML, or better yet post the code live on something like Codepen or CodeSandbox.

Are you looping over what querySelectorAll returns? It will be a NodeList (array like) containing all the elements that were matched.

Hi, thanks for support, here’s the HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="stylesheets/css/style.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta2/css/all.min.css">
  
    <title>Document</title>
</head>
<body>
  
 


      <div class="audio-player">

  <audio id="audio">
    <source src="sound/1.mp3">
  </audio>
        
        <div class="timeline">
          <div class="progress"></div>
        </div>
        
        <div class="controls">

          <div class="play-container">
            <div class="toggle-play fas fa-play">
          </div>
          </div>
          
          <div class="time">
            <div class="current">0:00</div>
            <div class="divider">/</div>
            <div class="length"></div>
          </div>
          
      
          <div class="volume-container">
            <div class="volume-button">
              <div class="volume"></div>
            </div>
            <div class="volume-slider">
              <div class="volume-percentage"></div>
            </div> 
          </div>  

          <select id="speedlist">
            <option value="1"></option>
            <option value=".5">0.5</option>
            <option value="1.5">1.5</option>
            <option value="2">2</option>
          </select>

        </div>
      </div>


  



    <script src="script.js"></script>

</body>
</html>

I only see one player. In any case, all the code you have is set up to work with one player. If you use querySelectorAll you will get an array (NodeList) of all the players. You have to loop that array and attach the event listeners to each of the players.

Or you have to move the event listener up to a parent container and look at the event target (event delegation).

Thanks for your guidance’s link…
here’s the codepen website
could you fix it for me ?

I won’t just fix it.

We are a learning platform. You should learn how to do it and understand why it works or doesn’t work. Otherwise, you will just have unmaintainable code.


You have multiple elements they each need their own handlers and reference to the source.

  1. Get all the .audio-player elements and loop them.

  2. Move all the code inside the loop.

  3. Change the source ids to classes (or data attributes).

const audioPlayers = document.querySelectorAll(".audio-player");

audioPlayers.forEach((audioPlayer) => {
  // audioPlayer is each audio-player element
  
  // after changeing the audio id to a class with the same name
  // you can get each audio element using the same selector
  const audio = audioPlayer.querySelector(".audio");
  
  // Move all the event listeners/handlers inside the loop.
  // As long as the forEach parameter is named audioPlayer it should all work
  
  ...code

});
1 Like