I am using 2 custom buttons and using JavaScript to click the audio play and pause.
I am using the below code for that:
<img class="head-iconn" src="img/audio.png" onClick="document.getElementById('audio1_play32').play(); return false;" />
<img class="head-icon2" src="img/audio2.png" onClick="document.getElementById('audio1_play32').pause(); return false;" />
But I want to stop the audio instead of pause so that when I play it again, it'll start from the beginning.
I am using this code for that:
<img class="head-iconn" src="img/audio.png" onClick="document.getElementById('audio1_play32').play(); return false;" />
<img class="head-icon2" src="img/audio2.png" onClick="document.getElementById('audio1_play32').pause(); document.getElementById('audio1_play32').currentTime = 0;return false;" />
and now the audio stops but can not play again when I click on the first button.
This is the audio code I am using:
<audio id="audio1_play32" controls>
<source src="voice/vo1.mp3" type="audio/mp3"/>
</audio>
Can someone please let me know what I am making mistake?
Thank you.
Update
Although not part of the question OP asked,
"What is I have multiple audios on a single page?"
Simply place the event handler on an element that contains all of the <button>s. Then get the reference to a specific <audio> by proximity of clicked <button>(event.target):
<audio><!--mp3 = btnGroup.previousElementSibling--></audio>
<fieldset>
<!--btnGroup = clicked.parentElement-->
<button><!--clicked = event.target--></button>
</fieldset>
Stay away from using attribute event handlers:
<!-- This is bad -->
<button class='play' onclick='playAudio()'>PLAY</button>
Use .addEventListener()
<button class='play'>PLAY</button>
<script>
const play = document.querySelector('.play');
play.addEventListener('click', playAudio);
</script>
or property event handlers:
<button class='play'>PLAY</button>
<script>
const play = document.querySelector('.play');
play.onclick = playAudio;
</script>
See Event Handlers
Keep your JavaScript separate from HTML or you'll cripple the growth of your code. The example below uses event delegation to determine which button was clicked and what happens according to what was clicked.
const main = document.querySelector('main');
const audioControl = event => {
const clicked = event.target;
const btnGroup = clicked.parentElement;
const mp3 = btnGroup.previousElementSibling;
if (clicked.matches('.play') && !mp3.paused) {
mp3.pause();
} else if (clicked.matches('.play') && !mp3.playing) {
mp3.play();
} else if (clicked.matches('.stop')) {
mp3.pause();
mp3.currentTime = 0;
} else {
return false;
}
};
main.onclick = audioControl;
button {
border: 0;
cursor: pointer;
font-size: 4ch
}
fieldset {
display: inline-block;
}
<main>
<audio src='https://soundbible.com/mp3/thunder_strike_1-Mike_Koenig-739781745.mp3'></audio>
<fieldset>
<button class='play'>⏯️</button>
<button class='stop'>⏹️</button>
</fieldset>
<audio src='https://soundbible.com/mp3/airplane-landing_daniel_simion.mp3'></audio>
<fieldset>
<button class='play'>⏯️</button>
<button class='stop'>⏹️</button>
</fieldset>
<audio src='https://soundbible.com/mp3/old-car-engine_daniel_simion.mp3'></audio>
<fieldset>
<button class='play'>⏯️</button>
<button class='stop'>⏹️</button>
</fieldset>
</main>
Related
i want to build a image button, that plays an audio.
My Version works but when I want to use it more than once on a site, it only play one mp3, not the other ones.
My Code:
<audio loop="false" src="audio_01.mp3"> </audio>
<p><img alt="" class="hover_pic" src="image.png" style="width: 40%;cursor:pointer" /></p>
<script>
var aud = document.getElementById("ASong").children[0];
var isPlaying = false;
aud.pause();
function playPause() {
if (isPlaying) {
aud.pause();
} else {
aud.play();
}
isPlaying = !isPlaying;
}
</script></div>
and
<div id="BSong" onclick="playPause()" type="button">
<audio loop="false" src="audio_02.mp3"> </audio>
<p><img alt="" class="hover_pic" src="image.png" style="width: 40%;cursor:pointer" /></p>
<script>
var aud = document.getElementById("BSong").children[0];
var isPlaying = false;
aud.pause();
function playPause() {
if (isPlaying) {
aud.pause();
} else {
aud.play();
}
isPlaying = !isPlaying;
}
</script></div>
So you have an idea what the problem is that the button only play one of them on the website?
You are using the same variable names multiple times like aud, isPlayig, etc..
To solve this issue, you should declare only once the whole script and form the onclick="playPause()" send the id of the song you want to play.
Be aware if there is already some music which is playing.
It's hard to tell how your two current code snippets are arranged with respect to each other, but duplicating the code over and over every time you want to add another track is going to be unmaintainable. As it stands, the variables for isPlaying and aud probably overwrite each other, depending on how they're laid out, even if they're in different scripts. Using const or let instead of var and use strict; at the top of your script can help detect these aliases.
You could add closures around each one to keep them distinct, but a better approach is to write a loop (which also acts as a scoping closure) and dynamically add the listener to each element. For example:
const trackEls = [...document.querySelectorAll(".track")];
for (const trackEl of trackEls) {
const audioEl = trackEl.querySelector("audio");
trackEl.addEventListener("click", () => {
audioEl.paused ? audioEl.play() : audioEl.pause();
});
}
<div class="tracks">
<div type="button" class="track">
<audio src="https://upload.wikimedia.org/wikipedia/commons/d/d8/Bourne_woods_2020-11-18_0732.mp3"></audio>
<img alt="play track icon" src="http://placekitten.com/50/50" class="track-icon">
</div>
<div type="button" class="track">
<audio src="https://upload.wikimedia.org/wikipedia/commons/e/ea/Rapid-Acoustic-Survey-for-Biodiversity-Appraisal-pone.0004065.s017.ogg"></audio>
<img alt="play track icon" src="http://placekitten.com/50/50" class="track-icon">
</div>
</div>
Note that the above code lets multiple audio files play at once. If you want to stop all other audio elements when a new one is clicked and reset their time, you can do that with a loop or an extra variable that keeps track of the currently-playing track. For example:
const trackEls = [...document.querySelectorAll(".track")];
let currentTrack;
for (const trackEl of trackEls) {
const audioEl = trackEl.querySelector("audio");
trackEl.addEventListener("click", () => {
if (audioEl !== currentTrack) {
if (currentTrack) {
currentTrack.pause();
currentTrack.currentTime = 0;
}
currentTrack = audioEl;
}
audioEl.paused ? audioEl.play() : audioEl.pause();
});
}
<div class="tracks">
<div type="button" class="track">
<audio src="https://upload.wikimedia.org/wikipedia/commons/d/d8/Bourne_woods_2020-11-18_0732.mp3"></audio>
<img alt="play track icon" src="http://placekitten.com/50/50" class="track-icon">
</div>
<div type="button" class="track">
<audio src="https://upload.wikimedia.org/wikipedia/commons/e/ea/Rapid-Acoustic-Survey-for-Biodiversity-Appraisal-pone.0004065.s017.ogg"></audio>
<img alt="play track icon" src="http://placekitten.com/50/50" class="track-icon">
</div>
</div>
A few remarks on your code:
There's no need for isPlaying variables since audio elements already track their playing/paused state with audioElement.paused. If you track it in external state, you add further complication and room for bugs if your variable and the the audio element's state go out of sync.
Avoid putting a <script> in a <div>. <script> is usually a child of <body> or <head> (probably <body> in this case), after all of the HTML tags are closed.
onclick on an HTML element is generally poor practice. HTML should be structural, not behavioral. Similarly, style="width: 40%;cursor:pointer" should be moved to an external stylesheet and applied to a class.
.children[0]; is a brittle way to select the audio element in a track. If you wind up rearranging elements in the div, this code is liable to break. document.querySelector("#BSong audio") is more precise and robust to refactors, although using classes instead of ids enables easier dynamism so you don't have to type each track out by hand.
CSS classes are usually kebab-case, so hover_pic would be hover-pic.
I am trying to have users click a play button, watch a case study video, and have the video go back to its original state once done playing. The issue is that when adding multiple case studies on one page the getElementById(), not only is invalid HTML, but it also plays the wrong case study video or it won't play at all.
I read online that getElementsByName or getElementsByClassName could be an alternative, but I can't get them to work.
Case study HTML block (this gets repeated on the page)
<div class="caseStudy">
<button id="playButton"></button>
<div id="casestudyPoster" class="caseStudy_poster"></div>
<iframe class="caseStudy_video" src="<vimeo-url-here>" width="100%" height="100%" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" webkitallowfullscreen mozallowfullscreen allowfullscreen>
</iframe>
</div>
JavaScript:
var poster = document.getElementById("casestudyPoster");
var button = document.getElementById("playButton");
poster.onclick = function() { fadeImage() };
button.onclick = function() { fadeImage() };
function fadeImage() {
poster.style.visibility = "hidden";
button.style.visibility = "hidden";
var iframe = document.querySelector('iframe');
var player = new Vimeo.Player(iframe);
player.play();
player.on('ended', function(data){
poster.style.visibility = "visible";
button.style.visibility = "visible";
});
}
How can I get this JavaScript to work with multiple caseStudys?
The issue is you are binding your JavaScript functionality to only one element, whereas you desire to bind your JavaScript functionality to multiple elements.
Here is an example of A) collecting several similar elements B) binding unique events to their unique properties.
// Gather all your similar elements
const videoElements = document.querySelectorAll( '.video-element' );
// For each element, let's do something with it.
videoElements.forEach( ( vidEl ) => {
// For this current element, lets create useful variables from elements found within it.
const playButton = vidEl.querySelector( '.play-button' );
const dynamicText = vidEl.querySelector( '.dynamic-text' );
// For this current element's play button, let's bind a unique event to it.
playButton.onclick = () => { dynamicText.innerHTML = `Video Playing!` };
} );
.video-element {
border: 1px solid;
margin: 1rem;
}
<div class="video-element">
<h2>Video 1</h2>
<button class="play-button">Play</button>
<span class="dynamic-text">I have my own functionality!</span>
</div>
<div class="video-element">
<h2>Video 2</h2>
<button class="play-button">Play</button>
<span class="dynamic-text">I have my own functionality!</span>
</div>
<div class="video-element">
<h2>Video 3</h2>
<button class="play-button">Play</button>
<span class="dynamic-text">I have my own functionality!</span>
</div>
<div class="video-element">
<h2>Video 4</h2>
<button class="play-button">Play</button>
<span class="dynamic-text">I have my own functionality!</span>
</div>
I'm trying to make it so that when you click on a separate element it pauses the current song playing from a different element. In addition I had previously made it so when you click on the same element after it started playing audio it would pause that audio, but when you click on a different element with the same function it breaks.
var paused = true;
var song;
var songPlaying;
function playSong(x) {
song = x;
if(songPlaying != song){
document.getElementById(songPlaying).pause();
}
if(paused == true){
document.getElementById(song).play();
paused = false;
songPlaying = song;
} else {
document.getElementById(song).pause();
paused = true;
}
}
Is there anyway I can fix this? Will I have to make a different function for every song?
EDIT 1: Here the HTML my for the sections I'm using as well, each audio file has an ID that is called as a parameter in the function inside onclick
<div class="album">
<img src="assets/BattalionsOfFear.png" onclick="playSong('bofSong')">
<h1>Battalions of Fear</h1>
<p>Released in 1988</p>
</div>
<div class="album">
<img src="assets/FollowTheBlind.png" onclick="playSong('bfsSong')">
<h1>Follow the Blind</h1>
<p>Released in 1989</p>
</div>
<!--- Audio -->
<audio id="bofSong">
<source src="assets/BattalionsOfFear.mp3">
</audio>
<audio id="bfsSong">
<source src="assets/BanishFromSanctuary.mp3">
</audio>
EDIT 2:
In attempting Laif's solution
I have tried adding the 'song' class to my HTML img elements and linked it to my audio element with the 'song1' class yet it still is not working. Am I doing the classes wrong or is it something with the way I have put them down?
<div class="album">
<img src="assets/BattalionsOfFear.png" class="song song1">
<h1>Battalions of Fear</h1>
<p>Released in 1988</p>
</div>
<audio id="bofSong" class="song1">
<source src="assets/BattalionsOfFear.mp3">
</audio>
Each song should share the same class so that you can do something like this:
<html>
<div class="song"></div>
<div class="song"></div>
</html>
var songs = document.querySelectorAll(".song");
function playSong(e) {
songs.forEach(el => {
el.style.play();
});
e.currentTarget.pause();
};
songs.forEach(el => {
el.addEventListener("click", playSong);
});
Right now, I have this code on my website:
<audio src="http://204.2.199.166/7/288/80873/v1/rogers.akacast.akamaistream.net/tor925"
controls="true"
volume="1.0">
</audio>
Which displays the default audio player like this.
But my desired outcome is to only have the play/pause functionality. Something like this.
I did some research and found the closest code to my desired outcome here. I tried to run these code on my Wix website under the Edit Code window but nothing seems to work at all.
What would be the simplest way to achieve this?
I'm a beginner so any help would be appreciated. Thanks in advance :)
This should work:
let button = document.querySelector('.trigger-audio')
let audio = document.querySelector('audio')
button.addEventListener('click',() =>{
if(button.classList.contains('fa-play')){
audio.play()
button.classList.remove('fa-play')
button.classList.add('fa-pause')
}else{
audio.pause();
button.classList.remove('fa-pause')
button.classList.add('fa-play')
}
})
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<span class="trigger-audio fa fa-play">
<audio src="http://204.2.199.166/7/288/80873/v1/rogers.akacast.akamaistream.net/tor925"
volume="1.0">
</audio>
</span>
Solution for multiple buttons [update]
First of all, we wrap the audio tags inside a container.
<div class="container">
<span class="trigger-audio fa fa-play">
<audio src="http://204.2.199.166/7/288/80873/v1/rogers.akacast.akamaistream.net/tor925"
volume="1.0">
</audio>
</span>
<span class="trigger-audio fa fa-play">
<audio src="https://cbc_r2_tor.akacast.akamaistream.net/7/364/451661/v1/rc.akacast.akamaistream.net/cbc_r2_tor"
volume="1.0">
</audio>
</span>
</div>
then we create a simple function that return in an array all of the sibling of a element(using es6 features):
function getAllSiblings(el){
let parent = el.parentElement
let children = Array.from(parent.children)
let siblings = children.filter(child => {
return child !== el
})
return siblings
}
then we catch all audio tags and put them in an arraylike object with let buttons = document.querySelectorAll('.trigger-audio')
Now whe loop over this collection and for every element of the collection (aka for every button) we attach on it a click event listener where, once the button is clicked :
we get all his sibling (in our case is only one): let siblings = getAllSiblings(button)
then we catch his direct children: let audio = button.children[0], for every button there is only one children so we can use this method, the direct children is the audio tag we want play
Now we check if the the button itself has the class fa-play, if it does means that the button is not playng yet, so we play it, we remove the fa-play class and replace it with the fa-pause class, we also disable all his siblings. So they don't will be played if the current button is playing.
On the contrary, if the button has the class fa-pause means that the button is currently playing, and we operate the inverse operations on it:
restore the click on his siblings,
pause the audio,
give the button the fa-play class
Of course this is a simple implementation, for more advance and maybe robust one, I suggest to take a look into the MediaElement docs
function getAllSiblings(el){
let parent = el.parentElement
let children = Array.from(parent.children)
let siblings = children.filter(child => {
return child !== el
})
return siblings
}
let buttons = document.querySelectorAll('.trigger-audio')
buttons.forEach(button =>{
let siblings = getAllSiblings(button)
let audio = button.children[0]
button.addEventListener('click',function(){
if(button.classList.contains('fa-play')){
audio.play()
button.classList.remove('fa-play')
button.classList.add('fa-pause')
siblings.forEach(sibling=>{
sibling.style.pointerEvents = "none"
})
}else{
audio.pause();
button.classList.remove('fa-pause')
button.classList.add('fa-play');
siblings.forEach(sibling =>{
sibling.style.pointerEvents = "auto"
})
}
})
})
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<div class="container">
<span class="trigger-audio fa fa-play">
<audio src="http://204.2.199.166/7/288/80873/v1/rogers.akacast.akamaistream.net/tor925"
volume="1.0">
</audio>
</span>
<span class="trigger-audio fa fa-play">
<audio src="https://cbc_r2_tor.akacast.akamaistream.net/7/364/451661/v1/rc.akacast.akamaistream.net/cbc_r2_tor"
volume="1.0">
</audio>
</span>
</div>
Dinamically switch play/pause
function getAllSiblings(el){
let parent = el.parentElement
let children = Array.from(parent.children)
let siblings = children.filter(child => {
return child !== el
})
return siblings
}
let stop = document.querySelector('.fa-stop')
let buttons = document.querySelectorAll('.trigger-audio')
stop.addEventListener('click',function(){
buttons.forEach(button =>{
let audio = button.firstElementChild
if(!audio.paused){
audio.pause()
button.classList.add('fa-play')
button.classList.remove('fa-pause')
}
})
})
buttons.forEach(button =>{
let audio = button.firstElementChild
let siblings = getAllSiblings(button)
button.addEventListener('click',function(){
audio.play()
button.classList.remove('fa-play')
button.classList.add('fa-pause')
siblings.forEach(sibling =>{
let siblingAudio = sibling.firstElementChild
sibling.addEventListener('click',function(){
siblingAudio.play()
audio.pause()
sibling.classList.remove('fa-play')
sibling.classList.add('fa-pause')
button.classList.remove('fa-pause')
button.classList.add('fa-play')
})
})
})
})
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<div class="container">
<span class="trigger-audio fa fa-play">
<audio src="http://204.2.199.166/7/288/80873/v1/rogers.akacast.akamaistream.net/tor925"
volume="1.0">
</audio>
</span>
<span class="trigger-audio fa fa-play">
<audio src="https://cbc_r2_tor.akacast.akamaistream.net/7/364/451661/v1/rc.akacast.akamaistream.net/cbc_r2_tor"
volume="1.0">
</audio>
</span>
</div>
<span class="fa fa-stop"></span>
An <audio> tag isn't visible if you remove the controls attribute or give it a false value. In it's place, you can design a <button>, link, div, etc. as the <audio> tag's interface. Note: this code requires no extra files to load, it is pure JavaScript and the icons are standard to every browser and system that accepts utf-8.
Demo
var btn = document.getElementById('btn');
var player = document.getElementById('player');
btn.addEventListener('click', playPause, false);
function playPause(e) {
if (player.paused || player.ended) {
player.play();
this.classList.add('playing');
this.classList.remove('paused');
} else {
player.pause();
this.classList.add('paused');
this.classList.remove('playing');
}
}
#btn {
display: block;
width: 48px;
height: 48px;
border-radius: 50%;
border: 3px ridge grey;
cursor:pointer;
outline:none
}
#btn::before {
content: '';
font-size:48px;
display:block;
margin-top:-15px;
}
#btn.paused::before {
content:'▶'
}
#btn.playing::before {
content: '⏸';
margin-left:-8.5px;
margin-top:-18px;
}
<audio id='player' src='http://204.2.199.166/7/288/80873/v1/rogers.akacast.akamaistream.net/tor925'></audio>
<button id='btn' class='paused'></button>
I want display an audio player, after click a button. here my code
<script type="text/javascript">
function viewAudio() {
document.getElementById('myAudio').style.display = ""
}
document.getElementById('myAudio').style.display = "none"
</script>
<button value="#Html.DisplayFor(modelItem => item.SampleURL)" id="audioViewer" onclick="viewAudio()">
<img src="../../Content/images/audio.png"></button>
<div id="myAudio">
<audio controls preload="none">
<source src="#" type="audio/mp3">
</audio>
</div>
But, when i run in browser it still display the audio player.
any solution for this?
First of all, to have the player hidden by default you don't need to use JavaScript. Add such style to the container instead:
<div id="myAudio" style="display: none;">
And to show it back upon clicking the button:
function viewAudio() {
document.getElementById('myAudio').style.display = "block";
}
If this is an ASP page then that button click might be doing a postback. This will reset the state. You should have either return false; at the end of the onclick.
Alternatively, if the problem is that the div is never hidden, you can set the style directly on the div element in the html markup.
Make sure that you are using your browser's development tools to check the css styling currently on the element you're looking at. You can also set breakpoints and step through your javascript code, right in your browser.
<asp:Button ID="ButtonShowPanel" CausesValidation="false" CssClass="btn btn-primary pull-right" runat="server" Text="Add Contact" OnClientClick="javascript:SetVisiblityPanels(false); return false;" />
function SetVisiblityPanels(check) {
if (check) {
$('.SearchPanel').show(1000);
$('.DescriptionPanel').hide(1000);
}
else {
$('.SearchPanel').hide(1000);
$('.DescriptionPanel').show(1000);
}
}
<script type="text/javascript">
function CheckVisiblityPanels(check) {
if (check) {
{
document.getElementById('<%=myAudio.ClientID%>').style.display = "block";
}
else
{
document.getElementById('<%=myAudio.ClientID%>').style.display = "none";
}
return false;
}
};
</script>