Search code examples
javascripthtmlfrontendhtml5-audio

How can I use parentNode with add/removeClass and an IF argument for <audio>?


I have multiple <audio> containers. When pressing 'Play' I want to target the parent audio container to play instead of all the other containers.

Each time I press the play button, all the audio containers fire and start playing. What I want is to target the parent container of the pressed button and only play that container.

I understand that I can use parentNode for this but whenever I implement it, I get an error, whether I use it for the IF argument or the add/removeClass syntax.

function playAudio(val) {
  var aud = $("audio")[val - 1];

  if (aud.paused) {
    aud.play();
    aud.loop = false;
    $(".play-pause").removeClass("icon-play");
    $(".play-pause").addClass("icon-stop");
  } else {
    aud.pause();
    $(".play-pause").removeClass("icon-stop");
    $(".play-pause").addClass("icon-play");
  }

  aud.ontimeupdate = function () {
    $(".progress")
      .css("width", (aud.currentTime / aud.duration) * 100 + "%");

    var mins = Math.floor(aud.currentTime / 60);
    if (mins < 10) {
      mins = "0" + String(mins);
    }
    var secs = Math.floor(aud.currentTime % 60);
    if (secs < 10) {
      secs = "0" + String(secs);
    }

    $(".timestamp")
      .text(mins + ":" + secs);
  };
}
.player {
  position: relative;
  display: flex;
  border-radius: 0px;
  padding: 5 16px;
}

.player .info {
  display: flex;
  flex-flow: column nowrap;
  justify-content: center;
  width: 50%;
  padding: 0 16px;
}

.player .info .name {
  font-size: 15px;
  font-weight: 700;
}

.player .info .singer {
  font-size: 12px;
}

.player .audioBtns {
  width: 50%;
  /*align-items: center;*/
  padding: 0 16px;
}

.player .audioBtns div:nth-child(1) {
  font-size: 30px;
}

.player .audioBtns div:nth-child(2),
.player .audioBtns div:nth-child(3) {
  font-size: 18px;
}

.player .progress {
  position: absolute;
  height: 5px;
  left: 0;
  bottom: 0;
  background-color: #f8f9fa;
  border-radius: 0px;
}

.icon-loop {
  content: url("loop.svg");
  width: 20px;
  height: 20px;
  display: block;
}

.icon-play:before {
  content: url("https://image.flaticon.com/icons/svg/860/860768.svg");
  width: 30px;
  height: 45px;
  display: block;
}

.icon-stop:before {
  content: url("https://image.flaticon.com/icons/svg/633/633940.svg");
  width: 30px !important;
  height: 40px !important;
  display: block;
}

.playBtn {
  padding: 0 16px;
}

.activeOverlay {
  filter: invert(42%) sepia(11%) saturate(1216%) hue-rotate(279deg)
    brightness(88%) contrast(85%);
}

.audioContainer {
  background-color: #d3d3d3;
  padding: 2% 2% !important;
}

.audioContainer:not(:last-child) {
  margin-bottom: 3%;
}

.audioContainerActive {
  background-color: #855b6f !important;
  color: #f8f9fa !important;
}

.IconActive {
  filter: invert(92%) sepia(17%) saturate(3434%) hue-rotate(186deg)
    brightness(127%) contrast(95%);
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- First Audio Container. OnClick on Line 5 -->
<div class="row no-gutters d-flex flex-column col-12">
  <div class="col d-flex flex-column justify-content-xl-center audioContainer">
    <div class="player">
      <div class="d-flex flex-row align-items-xl-center playBtn" onclick="playAudio(1)"><i class="fas fa-pause iconfont play-pause icon-play"></i></div><audio src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3" type="audio/mpeg"></audio>
      <div class="info">
        <div class="name">
          <p id="qwewq">By The Shell</p>
        </div>
        <div class="singer">
          <p>Adam M.</p>
        </div>
      </div>
      <div class="d-flex flex-row justify-content-around justify-content-xl-end align-items-xl-center audioBtns">
        <p class="timestamp" style="font-size: 20px;margin-bottom: 0px;">00:00</p>
      </div>
      <div data-toggle="tooltip" id="progressBar" class="progress"></div>
    </div>
  </div>

  <!-- Second Audio Container. OnClick on Line 25 -->

  <div class="col d-flex flex-column justify-content-xl-center audioContainer">
    <div class="player">
      <div class="d-flex flex-row align-items-xl-center playBtn" onclick="playAudio(2)"><i class="fas fa-pause iconfont play-pause icon-play"></i></div><audio src="https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_700KB.mp3" type="audio/mpeg"></audio>
      <div class="info">
        <div class="name">
          <p id="qwewq-1">Turntable</p>
        </div>
        <div class="singer">
          <p>Adam M.</p>
        </div>
      </div>
      <div class="d-flex flex-row justify-content-around justify-content-xl-end align-items-xl-center audioBtns">
        <p class="timestamp" style="font-size: 20px;margin-bottom: 0px;">00:00</p>
      </div>
      <div data-toggle="tooltip" id="progressBar-1" class="progress"></div>
    </div>
  </div>
</div>


Solution

  • Run the operation only on selected container using jQuery eq() method

    Main changes:

    if (aud.paused) {
            aud.play();
            aud.loop = false;
            $(".play-pause").eq(val - 1).removeClass("icon-play"); // added .eq(val)
            $(".play-pause").eq(val - 1).addClass("icon-stop");
          } else {
            aud.pause();
            $(".play-pause").eq(val - 1).removeClass("icon-stop");
            $(".play-pause").eq(val - 1).addClass("icon-play");
          }
    // -----------
    $(".progress").eq(val - 1).css("width", (aud.currentTime / aud.duration) * 100 + "%");
    // -----------
    $(".timestamp").eq(val - 1).text(mins + ":" + secs);
    

    Working Example Below :

    function playAudio(val) {
      var aud = $("audio")[val - 1];
    
      if (aud.paused) {
        aud.play();
        aud.loop = false;
        $(".play-pause").eq(val - 1).removeClass("icon-play");
        $(".play-pause").eq(val - 1).addClass("icon-stop");
      } else {
        aud.pause();
        $(".play-pause").eq(val - 1).removeClass("icon-stop");
        $(".play-pause").eq(val - 1).addClass("icon-play");
      }
    
      aud.ontimeupdate = function() {
        $(".progress").eq(val - 1)
          .css("width", (aud.currentTime / aud.duration) * 100 + "%");
    
        var mins = Math.floor(aud.currentTime / 60);
        if (mins < 10) {
          mins = "0" + String(mins);
        }
        var secs = Math.floor(aud.currentTime % 60);
        if (secs < 10) {
          secs = "0" + String(secs);
        }
    
        $(".timestamp").eq(val - 1)
          .text(mins + ":" + secs);
      };
    }
    .player {
      position: relative;
      display: flex;
      border-radius: 0px;
      padding: 5 16px;
    }
    
    .player .info {
      display: flex;
      flex-flow: column nowrap;
      justify-content: center;
      width: 50%;
      padding: 0 16px;
    }
    
    .player .info .name {
      font-size: 15px;
      font-weight: 700;
    }
    
    .player .info .singer {
      font-size: 12px;
    }
    
    .player .audioBtns {
      width: 50%;
      /*align-items: center;*/
      padding: 0 16px;
    }
    
    .player .audioBtns div:nth-child(1) {
      font-size: 30px;
    }
    
    .player .audioBtns div:nth-child(2),
    .player .audioBtns div:nth-child(3) {
      font-size: 18px;
    }
    
    .player .progress {
      position: absolute;
      height: 5px;
      left: 0;
      bottom: 0;
      background-color: #f8f9fa;
      border-radius: 0px;
    }
    
    .icon-loop {
      content: url("loop.svg");
      width: 20px;
      height: 20px;
      display: block;
    }
    
    .icon-play:before {
      content: url("https://image.flaticon.com/icons/svg/860/860768.svg");
      width: 30px;
      height: 45px;
      display: block;
    }
    
    .icon-stop:before {
      content: url("https://image.flaticon.com/icons/svg/633/633940.svg");
      width: 30px !important;
      height: 40px !important;
      display: block;
    }
    
    .playBtn {
      padding: 0 16px;
    }
    
    .activeOverlay {
      filter: invert(42%) sepia(11%) saturate(1216%) hue-rotate(279deg) brightness(88%) contrast(85%);
    }
    
    .audioContainer {
      background-color: #d3d3d3;
      padding: 2% 2% !important;
    }
    
    .audioContainer:not(:last-child) {
      margin-bottom: 3%;
    }
    
    .audioContainerActive {
      background-color: #855b6f !important;
      color: #f8f9fa !important;
    }
    
    .IconActive {
      filter: invert(92%) sepia(17%) saturate(3434%) hue-rotate(186deg) brightness(127%) contrast(95%);
    }
    <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <!-- First Audio Container. OnClick on Line 5 -->
    <div class="row no-gutters d-flex flex-column col-12">
      <div class="col d-flex flex-column justify-content-xl-center audioContainer">
        <div class="player">
          <div class="d-flex flex-row align-items-xl-center playBtn" onclick="playAudio(1)"><i class="fas fa-pause iconfont play-pause icon-play"></i></div><audio src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3" type="audio/mpeg"></audio>
          <div class="info">
            <div class="name">
              <p id="qwewq">By The Shell</p>
            </div>
            <div class="singer">
              <p>Adam M.</p>
            </div>
          </div>
          <div class="d-flex flex-row justify-content-around justify-content-xl-end align-items-xl-center audioBtns">
            <p class="timestamp" style="font-size: 20px;margin-bottom: 0px;">00:00</p>
          </div>
          <div data-toggle="tooltip" id="progressBar" class="progress"></div>
        </div>
      </div>
    
      <!-- Second Audio Container. OnClick on Line 25 -->
    
      <div class="col d-flex flex-column justify-content-xl-center audioContainer">
        <div class="player">
          <div class="d-flex flex-row align-items-xl-center playBtn" onclick="playAudio(2)"><i class="fas fa-pause iconfont play-pause icon-play"></i></div><audio src="https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_700KB.mp3" type="audio/mpeg"></audio>
          <div class="info">
            <div class="name">
              <p id="qwewq-1">Turntable</p>
            </div>
            <div class="singer">
              <p>Adam M.</p>
            </div>
          </div>
          <div class="d-flex flex-row justify-content-around justify-content-xl-end align-items-xl-center audioBtns">
            <p class="timestamp" style="font-size: 20px;margin-bottom: 0px;">00:00</p>
          </div>
          <div data-toggle="tooltip" id="progressBar-1" class="progress"></div>
        </div>
      </div>
    </div>

    jQuery eq() method

    • The jQuery eq() method is used to get an element with a specific index of the selected HTML element. You can give either positive or negative integer value as index. The index of the first element of the matched element is 0. If we use selector.eq(-1), it will return the last element and selector.eq(0) will return the first element in the matched set of elements.
    • syntax - selector.eq(index)

    Reference : click_here