I want to use 6 of these Before/After Audio Players on my website: https://github.com/mattbartley/AB-Audio-Player
However, the sources of the audio files are set in the JavaScript code. So when I implement multiple instances of this player in my HTML, they all play the same two audio files. I want to set data attributes in the HTML code in each player div for the src of the files and let the JavaScript use that instead. How do I go about it?
<div class="player__wrapper" data-audio-before="Song-1-before.mp3" data-audio-after="Song-1-after.mp3">
...
<div class="player__wrapper" data-audio-before="Song-2-before.mp3" data-audio-after="Song-2-after.mp3">
...
And so on. This would be the updated HTML code.
I think it's a pretty basic solution, I'm just not good in JavaScript.
Here is the current JavaScript code:
//Set up audio elements
var soundA = document.createElement("audio");
//Set audio A src here
soundA.src = "./assets/a.mp3";
soundA.preload = "auto";
soundA.setAttribute("hidden", "true");
soundA.setAttribute("onplaying", "stepA()");
document.body.append(soundA);
var soundB = document.createElement("audio");
//Set audio B src here
soundB.src = "./assets/b.mp3";
soundB.preload = "auto";
soundB.setAttribute("hidden", "true");
soundB.setAttribute("onplaying", "stepB()");
document.body.append(soundB);
I tried something like this: Hover over div, use its data-attribute to change the src of an img And other approaches as well. Couldn't get it to work.
I forked the Matt Bartley 's AB-Audio-Player - not great but it works with multiple instances:
As commented, the player initialization is done within a forEach
loop.
All elements are selected by class names to avoid non unique IDs and relative element selection.
So you need to update your HTML template accordingly.
let players = document.querySelectorAll(".player__wrapper");
initPlayers(players);
function initPlayers(players) {
players.forEach((player) => {
//Get button elements
const playBtns = player.querySelectorAll(".ab__button");
const aButton = player.querySelector(".a__button");
const bButton = player.querySelector(".b__button");
const playButton = player.querySelector(".play__button");
const stopButton = player.querySelector(".stop__button");
const progressBar = player.querySelector(".progress__bar");
const progressFill = player.querySelector(".progress__fill");
// set icons
const playIcon = '<i class="fa-solid fa-play"></i>';
const pauseIcon = '<i class="fa-solid fa-pause"></i>';
const stopIcon = '<i class="fa-solid fa-stop"></i>';
//Default loading state for each sound
var soundAReady = false;
var soundBReady = false;
//Set up audio elements
var soundA = document.createElement("audio");
soundA.src = player.getAttribute("data-sound-a");
soundA.preload = "auto";
soundA.setAttribute("hidden", "true");
player.append(soundA);
var soundB = document.createElement("audio");
soundB.src = player.getAttribute("data-sound-b");
soundB.preload = "auto";
soundB.setAttribute("hidden", "true");
player.append(soundB);
//playSoundA
aButton.addEventListener("click", (e) => {
pauseAll();
playButton.innerHTML = pauseIcon;
aButton.disabled = true;
bButton.disabled = false;
stopButton.disabled = false;
soundA.currentTime = soundB.currentTime;
soundA.play();
});
//playSoundB
bButton.addEventListener("click", (e) => {
pauseAll();
playButton.innerHTML = pauseIcon;
bButton.disabled = true;
aButton.disabled = false;
stopButton.disabled = false;
soundB.currentTime = soundA.currentTime;
soundB.play();
});
//playSoundA
soundA.addEventListener("playing", (e) => {
console.log("playing");
progressFill.style.width =
((soundA.currentTime / soundA.duration) * 100 || 0) + "%";
requestAnimationFrame(stepA);
});
//playSoundB
soundB.addEventListener("playing", (e) => {
console.log("playing B");
progressFill.style.width =
((soundB.currentTime / soundB.duration) * 100 || 0) + "%";
requestAnimationFrame(stepB);
});
// playPause
playButton.addEventListener("click", (e) => {
if (soundA.paused & soundB.paused) {
let soundATime = soundA.currentTime;
let soundBTime = soundB.currentTime;
if (soundATime >= soundBTime) {
soundA.play();
bButton.disabled = false;
aButton.disabled = true;
playButton.innerHTML = pauseIcon;
} else {
soundB.play();
bButton.disabled = true;
aButton.disabled = false;
playButton.innerHTML = pauseIcon;
}
stopButton.disabled = false;
} else {
playButton.innerHTML = playIcon;
soundA.pause();
soundB.pause();
}
});
// stop
stopButton.addEventListener("click", (e) => {
playButton.innerHTML = playIcon;
aButton.disabled = false;
bButton.disabled = true;
playButton.disabled = false;
stopButton.disabled = true;
soundA.pause();
soundA.currentTime = 0;
soundB.pause();
soundB.currentTime = 0;
});
//Check for mobile to enable audio playback without waiting for download status.
if (
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
)
) {
playButton.disabled = false;
}
//Default loading state for each sound
var soundAReady = false;
var soundBReady = false;
//When audio can play through (loaded), run the function to enable buttons
//The canplaythrough event will fire every time the audio switches, so the !soundA/BReady
//prevents additional checks
soundA.oncanplaythrough = function() {
if (!soundAReady) {
soundAReady = true;
audioIsReady();
}
};
soundB.oncanplaythrough = function() {
if (!soundBReady) {
soundBReady = true;
audioIsReady();
}
};
// Check if both A & B are ready and enable the correct buttons
function audioIsReady() {
if (soundAReady && soundBReady) {
console.log("...audio loaded!");
aButton.disabled = false;
playButton.disabled = false;
} else {
console.log("Audio loading...");
}
}
const progress = player.querySelector(".progress");
// Listen for click on entire progress bar div (to allow skipping ahead)
progress.addEventListener("click", function(event) {
// Get X coordinate of click in div
var rect = this.getBoundingClientRect();
// Convert click position to percentage value
var percentage = (event.clientX - rect.left) / this.offsetWidth;
// Seek to the percentage converted to seconds
soundA.currentTime = percentage * soundA.duration;
soundB.currentTime = percentage * soundB.duration;
});
//Frame animations for progress bar fill - converts to CSS percentage
function stepA() {
progressFill.style.width =
((soundA.currentTime / soundA.duration) * 100 || 0) + "%";
requestAnimationFrame(stepA);
}
function stepB() {
progressFill.style.width =
((soundB.currentTime / soundB.duration) * 100 || 0) + "%";
requestAnimationFrame(stepB);
}
//Play/Stop correct audio and toggle A/B, Play/Pause, and Stop buttons
function playPause() {
if (soundA.paused & soundB.paused) {
let soundATime = soundA.currentTime;
let soundBTime = soundB.currentTime;
if (soundATime >= soundBTime) {
soundA.play();
bButton.disabled = false;
aButton.disabled = true;
playButton.innerHTML = pauseIcon;
} else {
soundB.play();
bButton.disabled = true;
aButton.disabled = false;
playButton.innerHTML = pauseIcon;
}
stopButton.disabled = false;
} else {
playButton.innerHTML = playIcon;
soundA.pause();
soundB.pause();
}
}
// optional: set auto ids
let allAudio = document.querySelectorAll("audio");
allAudio.forEach((audio, i) => {
audio.id = "audio_" + i;
});
// rewind all at end
allAudio.forEach((audio) => {
//audio.pause();
audio.addEventListener("ended", (e) => {
audio.currentTime = 0;
progressFill.style.width = "0%";
});
});
function pauseAll() {
let allAudio = document.querySelectorAll("audio");
allAudio.forEach((audio) => {
audio.pause();
});
}
});
}
<link href="https://fonts.googleapis.com/css2?family=Lato:wght@400;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==" crossorigin="anonymous" referrerpolicy="no-referrer"
/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/mattbartley/AB-Audio-Player@main/css/style.css" />
<div class="player__wrapper" data-sound-a="https://cdn.jsdelivr.net/gh/mattbartley/AB-Audio-Player@main/assets/a.mp3" data-sound-b="https://cdn.jsdelivr.net/gh/mattbartley/AB-Audio-Player@main/assets/b.mp3">
<div class="progress__container progress">
<div class="progress__bar progress__fill"></div>
</div>
<div class="ab__controls">
<button class="ab__button a__button" disabled="true">
A
</button>
<button class="ab__button b__button" disabled="true">
B
</button>
</div>
<div class="play__stop__controls">
<button class="play__pause__button play__button" disabled="true">
<i class="fa-solid fa-play"></i>
</button>
<button class="play__pause__button stop__button" disabled="true">
<i class="fa-solid fa-stop"></i>
</button>
</div>
</div>
<div class="player__wrapper" data-sound-a="https://cdn.jsdelivr.net/gh/mattbartley/AB-Audio-Player@main/assets/a.mp3" data-sound-b="https://cdn.jsdelivr.net/gh/mattbartley/AB-Audio-Player@main/assets/b.mp3">
<div class="progress__container progress">
<div class="progress__bar progress__fill"></div>
</div>
<div class="ab__controls">
<button class="ab__button a__button" disabled="true">
A
</button>
<button class="ab__button b__button" disabled="true">
B
</button>
</div>
<div class="play__stop__controls">
<button class="play__pause__button play__button" disabled="true">
<i class="fa-solid fa-play"></i>
</button>
<button class="play__pause__button stop__button" disabled="true">
<i class="fa-solid fa-stop"></i>
</button>
</div>
</div>