skip to Main Content

I tried to make a button, that transforms into an audio player.
I built the player first, and it worked fine, the range-slider and play/pause button worked.
I added the transformation of one type of button into the audio player.
But when the track starts automatically, after the button transforms, the play/pause button is not working anymore. It works fine if the track doesn’t start automatically (by removing the "playPause()"-function from the "startTrack()"-function).

I really would like the track to start automatically so that the user doesn’t have to click twice.

Thanks for your help!

let aGP = document.getElementById("audioGuidePlayer");
let interface = document.getElementById("interface");
let cover = document.getElementById("cover");

let progress = document.getElementById("progress");
let track = document.getElementById("track");
let playB = document.getElementById("playButton");

track.onloadedmetadata= function() {
    progress.max = track.duration;
    progress.value = track.currentTime;
}

function playPause(){
    if(playB.classList.contains("fa-pause")){
        track.pause();
        playB.classList.remove("fa-pause");
        playB.classList.add("fa-play");
    } else{
        track.play();
        playB.classList.remove("fa-play");
        playB.classList.add("fa-pause");
    }
}

function startTrack() {
    aGP.classList.remove("mainButton");
    aGP.classList.add("playerInterface");
    cover.classList.add("invis");
    interface.classList.remove("invis");
    playPause();
}

if(track.play()){
    setInterval(()=>{
        progress.value=track.currentTime;
    },500);
}

progress.onchange=function(){
    track.play();
    track.currentTime=progress.value;
    playB.classList.remove("fa-play");
    playB.classList.add("fa-pause");
}
*{
    margin: 0;
    padding: 0;
    font-family: 'Poppins',sans-serif;
    box-sizing: border-box;
}

:root{
    --mainColor:#67B023;
}

.container{
    width: 100%;
    height: 100vh;
    background: white;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    gap: 25px;
}

.mainButton{
    background: var(--mainColor);
    width: 300px;
    height: 70px;
    border-style: solid;
    border-width: 2px;
    border-color: black;
    border-radius: 40px;
    color: white;
    font-weight: bold;
    font-size: larger;
    text-align: center;
    display: flex;
    justify-content: center;
    align-items: center;
}

.mainButton i{
    padding-right: 10px;
}

.mainButton:focus{
    background-color: white;
}

.playerInterface{
    background-color: white;
    width:500px;
    height:70px;
    border-style: solid;
    border-width: 2px;
    border-color: black;
    border-radius: 40px;
    color: black;
    font-weight: bold;
    font-size: larger;
    text-align: center;
    display: flex;
    justify-content: center;
    flex-wrap: nowrap;
    align-items: center;
    flex-direction: row;
    padding-left: 10px;
    padding-right: 30px;
}

#progress{
    -webkit-appearance: none;
    width: 100%;
    height: 3px;
    background:black;
    border-radius: 4px;
    cursor: pointer;
}

#progress::-webkit-slider-thumb{
    -webkit-appearance: none;
    background: var(--mainColor);
    height: 20px;
    width: 20px;
    border-radius: 50%;
    border: 2px solid black;
}

.controls{
    display: flex;
    justify-content: center;
    align-items: center;
}

.controls div{
    width: 60px;
    height: 60px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    cursor: pointer;
}

.invis{
    display: none;;
}

#interface{
    width: 100%;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>audioGuideButton</title>
    <link rel="stylesheet" href="style.css">
    <script src="https://kit.fontawesome.com/8c4b6d78be.js" crossorigin="anonymous"></script>
</head>

<body>
    <div class="container">

        <div class="mainButton" id="audioGuidePlayer" onclick="startTrack()">
            <div id="cover">
                <i class="fa-solid fa-headphones fa-xl" style="color: #ffffff;"></i>
                listen to Audioguide
            </div>
            <div id="interface" class="invis">
                <audio id="track" >
                    <source src="media/A01 Klimakrise.mp3" type="audio/mpeg">
                </audio>
                <div class="controls">
                    <div onclick="playPause()">
                        <i class="fa-solid fa-play fa-xl" id="playButton"></i>
                    </div>
                    <input type="range" value="0" id="progress">
                </div>
            </div>
        </div>
    </div>
</body>

</html>

2

Answers


  1. The problem is that the startTrack function is still being called every time you click the playButton, as the playButton is a child of the audioGuidePlayer class. This means the playPause function is being called twice every time you click it, thus cancelling out its effects. Simply add this line of code to the startTrack function, right before playPause is called:

    aGP.removeAttribute('onclick');
    

    This will remove the startTrack function from the player. If at any point you need to convert the player back to its initial button state, be sure to set the onclick attribute to startTrack again.

    Login or Signup to reply.
  2. You only want the startTrack() function to call playPause() once.

    You could either guard the startTrack function:

    function startTrack() {
      const started = !!aGP.dataset.started;   // Flag
      if (!started) {                          // Guard
        aGP.classList.remove("mainButton");
        aGP.classList.add("playerInterface");
        cover.classList.add("invis");
        interface.classList.remove("invis");
        playPause();
        aGP.dataset.started = true;            // Initialized
      }
    }
    

    Or remove it:

    function startTrack() {
      aGP.classList.remove("mainButton");
      aGP.classList.add("playerInterface");
      cover.classList.add("invis");
      interface.classList.remove("invis");
      playPause();
      aGP.removeAttribute('onclick');         // Remove
    }
    

    Working example

    I also fixed your interval logic. The interval will only run while playing. It also updated every 100ms for a smoother progress bar.

    const aGP = document.getElementById("audioGuidePlayer");
    const interface = document.getElementById("interface");
    const cover = document.getElementById("cover");
    
    const progress = document.getElementById("progress");
    const track = document.getElementById("track");
    const playB = document.getElementById("playButton");
    
    let updateIntervalId;
    
    track.onloadedmetadata = function() {
      progress.max = track.duration;
      progress.value = track.currentTime;
    }
    track.onended = restartAction;
    
    function pauseAction() {
      clearInterval(updateIntervalId);
      track.pause();
      playB.classList.remove("fa-pause");
      playB.classList.add("fa-play");
    }
    
    function playAction() {
      clearInterval(updateIntervalId);
      track.play();
      playB.classList.remove("fa-play");
      playB.classList.add("fa-pause");
      updateIntervalId = setInterval(updateProgress, 100);
    }
    
    function restartAction() {
      clearInterval(updateIntervalId);
      progress.value = 0;
      playB.classList.remove("fa-pause");
      playB.classList.add("fa-play");
    };
    
    function playPause() {
      if (playB.classList.contains("fa-pause")) {
        pauseAction();
      } else {
        playAction();
      }
    }
    
    function startTrack() {
      const started = !!aGP.dataset.started;
      if (!started) {
        aGP.classList.remove("mainButton");
        aGP.classList.add("playerInterface");
        cover.classList.add("invis");
        interface.classList.remove("invis");
        playPause();
        aGP.dataset.started = true;
      }
    }
    
    function updateProgress() {
      progress.value = track.currentTime;
    }
    
    progress.onchange = function() {
      track.play();
      track.currentTime = progress.value;
      playB.classList.remove("fa-play");
      playB.classList.add("fa-pause");
    }
    * {
      margin: 0;
      padding: 0;
      font-family: 'Poppins', sans-serif;
      box-sizing: border-box;
    }
    
    :root {
      --mainColor: #67B023;
    }
    
    .container {
      width: 100%;
      height: 100vh;
      background: white;
      display: flex;
      justify-content: center;
      align-items: center;
      flex-direction: column;
      gap: 25px;
    }
    
    .mainButton {
      background: var(--mainColor);
      width: 300px;
      height: 70px;
      border-style: solid;
      border-width: 2px;
      border-color: black;
      border-radius: 40px;
      color: white;
      font-weight: bold;
      font-size: larger;
      text-align: center;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    
    .mainButton i {
      padding-right: 10px;
    }
    
    .mainButton:focus {
      background-color: white;
    }
    
    .playerInterface {
      background-color: white;
      width: 500px;
      height: 70px;
      border-style: solid;
      border-width: 2px;
      border-color: black;
      border-radius: 40px;
      color: black;
      font-weight: bold;
      font-size: larger;
      text-align: center;
      display: flex;
      justify-content: center;
      flex-wrap: nowrap;
      align-items: center;
      flex-direction: row;
      padding-left: 10px;
      padding-right: 30px;
    }
    
    #progress {
      -webkit-appearance: none;
      width: 100%;
      height: 3px;
      background: black;
      border-radius: 4px;
      cursor: pointer;
    }
    
    #progress::-webkit-slider-thumb {
      -webkit-appearance: none;
      background: var(--mainColor);
      height: 20px;
      width: 20px;
      border-radius: 50%;
      border: 2px solid black;
    }
    
    .controls {
      display: flex;
      justify-content: center;
      align-items: center;
    }
    
    .controls div {
      width: 60px;
      height: 60px;
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 50%;
      cursor: pointer;
    }
    
    .invis {
      display: none;
    }
    
    #cover:not(.invis):hover {
      cursor: pointer;
    }
    
    #interface {
      width: 100%;
    }
    <script src="https://kit.fontawesome.com/8c4b6d78be.js" crossorigin="anonymous"></script>
    <div class="container">
      <div class="mainButton" id="audioGuidePlayer" onclick="startTrack()">
        <div id="cover">
          <i class="fa-solid fa-headphones fa-xl" style="color: #ffffff;"></i>
          Listen to Audioguide
        </div>
        <div id="interface" class="invis">
          <audio id="track">
            <source src="https://upload.wikimedia.org/wikipedia/commons/b/bb/Test_ogg_mp3_48kbps.wav" type="audio/mpeg">
          </audio>
          <div class="controls">
            <div onclick="playPause()">
              <i class="fa-solid fa-play fa-xl" id="playButton"></i>
            </div>
            <input type="range" step="0.1" id="progress">
          </div>
        </div>
      </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search