I have been asked to update my question so here goes:
I have records in a database, some of which have wave file names attached. I am looping through the database and wanting to write out the word "Play" in a column under a header named Audio File. When "Play" is clicked on, the audio player plays the file and turns the href word to "Pause". When my code loops through these records, it is assigning a separate ID to each href. For me to call the function that starts the audio player, I need to send an audioControl ID (aControl) variable as well as the src source file (thissource) variable for the audio player - hence the & and " in the function call. When I use the onclick event in a button, it triggers the function. However, when I click the href link (which is what I want instead of a button) nothing happens. I am not sure which part of the code is messy, as I found the function code on the internet. Thank-you in advance for any and all help.
No matter what I do, my href onclick will not trigger a javascript function. I have taken the return false out of the function and put it in the href but that doesn't work either. I have put the same onclick code in a button and it triggers great.
HTML:
<a href='#' onclick='passvariables(" & aControl & "," & thissource & ");'>Play</a>
Javascript:
function passvariables(aControl, thissource)
{
var yourAudio= new Audio();
yourAudio.src = thissource;
yourAudio.type = 'audio/wav';
ctrl = document.getElementById(aControl);
ctrl.onclick = function ()
{
// Update the Button
var pause = ctrl.innerHTML === 'Pause';
ctrl.innerHTML = pause ? 'Play' : 'Pause';
// Update the Audio
var method = pause ? 'pause' : 'play';
yourAudio[method]();
// Prevent Default Action
return false;
}
}
Just have onclick call passvariables without the return and have passvariables return false.
You can try:
window.passvariables = function(aControl, thissource) {
// Your code
};
My guess if that your function is defined within another function (executed onload for instance). Hence "passvariables" is not defined in the "window" scope.
I saw you updated your questions that's good :)
First I recommend you to use the javascript library jquery which is easier to manipulate the DOM and you can easily find ressources and help on this site.
Here's what your code should look. I haven't tested it but it's a good overview of what this should be.
Put this in the <head> section of your HTML code
<script src="http://code.jquery.com/jquery-1.12.0.min.js"></script>
<script>
$(document).ready(function() {
//Assigning onClick function for every HTML tags having the css class "Play"
$('.Play').click(function(){
if($(this).html() == "Play"){
//retrieving information about the audio
var waveFile = $(this).attr("data-waveFile");
var audioId = $(this).attr("data-audioId");
//calling the startAudio function and assign the Audio object to myAudioObject
var myAudioObject = startAudio(waveFile, audioId);
if(myAudioObject){
//Audio started playing
$(this).html("Pause");
}else{
alert("error while starting to play file");
}
}else{
var isPaused = pauseAudio(myAudioObject);
if(isPaused){
//The pauseAudio function returned true so the audio is paused
$(this).html("Play");
}else{
alert("error while pausing");
}
}
});
//Functions to manage audio Player
function startAudio(waveFile, audioId){
audioObject = document.getElementById("audio");
audioObject.src = waveFile;
audioObject.play();
return true;
}
function pauseAudio(){
//do whatever to pause
audioObject = document.getElementById("audio");
audioObject.pause();
return true;
}
});
</script>
in the <body> section of your HTML code where you construct the table using database datas :
<table>
<tr>
<td>Song name</td>
<td>Action</td>
</tr>
<tr>
<td><%=WaveFile%></td>
<td>Play</td>
</tr>
</table>
<audio id="audio"></audio>
Note the <%=WaveFile%> and <%=AudioId%> should be the values you get from the database in your loop
Thank-you everyone for your help! I finally got it working! Here is the code:
yAudio = "'yourAudio" & thisline & "'"
aControl = "'audioControl" & thisline & "'"
thissource = "'/WaveFiles/" & RS.Fields("AudioIssues") &"'"
R"<td width=12 class=allprint>Play</td>"
// Call and play audio via JavaScript
$(document).ready(function()
{
var aElement = document.createElement('audio');
$('.Play').click(function()
{
if($(this).html() == "Play")
{
var waveFile = $(this).attr("data-waveFile");
var audioID = $(this).attr("data-audioId");
aElement.setAttribute('src', waveFile);
aElement.load()
aElement.addEventListener("load", function()
{
aElement.play();
$(this).html("Stop");
$(".duration span").html(aElement.duration);
$(".filename span").html(aElement.src);
}, true);
aElement.play();
$(this).html("Stop");
}
else
{
var waveFile = $(this).attr("data-waveFile");
var audioID = $(this).attr("data-audioId");
aElement.setAttribute('src', waveFile);
aElement.pause();
$(this).html("Play");
}
});
});
Related
I have a button on my website, which plays the music when you click on it and in the same time it changes the text inside of the button (to "Go to SoundCloud".)
I want that button (with the new text on it) to redirect to SoundCloud when I click on it.
Now I got both when click first time, which is redirect to SoundCloud and play the track. (plus it changes the text)
Any ideas, how to solve this problem? Thx!
var links = document.getElementById("playButton");
links.onclick = function() {
var html='<iframe width="100%" height="450" src="sourceOfMyMusic"></iframe>';
document.getElementById("soundCloud").innerHTML = html;
var newTexts = ["Go to SoundCloud"];
document.getElementById("playButton").innerHTML = newTexts;
newTexts.onclick = window.open('http://soundcloud.com/example');
};
Use a variable that indicates whether it's the first or second click.
var first_click = true;
links.onclick = function() {
if (first_click) {
// do stuff for first click
first_click = false;
} else {
// do stuff for second click
}
}
Just redefine the onclick after the first function call.
Put the onclick on the button instead of the html.
document.getElementById("playButton").onclick=window.open('http://soundcloud.com/example');
Another option in some cases is to use a ternary operator and a boolean toggle expression:
let btn = document.querySelector('.button');
let isToggledOn = false;
btn.addEventListener ('click', function(e) {
e.target.textContent = !isToggledOn ? 'Is ON' : 'Is OFF';
isToggledOn = !isToggledOn;
});
newTexts.onclick is not creating a function to open a window, it is simply taking the return value of window.open which is being executed right away.
It should look like:
newTexts.onclick = () => window.open('http://soundcloud.com/example');
Also this will not work as intended because newTexts is not the actual DOM element, you need to attach the new onclick on the element and not the array...
But to other answers in this page, the logic is hard to read, so I'd advise to refactor the logic to be more readable.
I have created a site with image thumbnails of people I have photographed. When a visitor clicks on one of the thumbnails the full image is revealed using jQuery, and an audio introduction plays. I have a different audio introduction for each thumbnail/image combination - 15 at present with more being added daily.
I would like to ensure that if a visitor clicks on another thumbnail before the previous audio file has completed, that the previous audio file is stopped/paused to allow the new audio file to be played - thereby ensuring two or more tracks do not play simultaneously.
I am currently using the following snippet of code, wrapped in an anonymous function, to play each audio file individually when the appropriate thumbnail is clicked - so this snippet is duplicated for each audio file, but don't know how to ensure they do not play over one another.
$(".bridget-strevens").click(function(){
var audio = $('#bridget-strevens-intro')[0];
if (audio.paused){
audio.play();
} else {
audio.pause();
}
});
Any help you could give me would be very grateful, as I am just starting to learn jQuery, and don't have the knowledge to come up with a workable solution.
Thanks in advance for your help!
Add a .audio class to all your audio elements and loop through all of them when an audio is clicked.
$(".bridget-strevens").click(function () {
$('.audio').each(function (index, value) {
if (!value.paused) {
value.pause();
}
});
var audio = $('#bridget-strevens-intro')[0];
if (audio.paused) {
audio.play();
} else {
audio.pause();
}
});
If that seems too heavy for you then simply add the audio element in a global variable such as:
var currentAudio;
Then when a new audio is clicked, simply pause that one, play the new one and update the currentAudio variable with the new element currently being played.
var currentAudio = null;
$(".bridget-strevens").click(function () {
if(currentAudio != null && !currentAudio.paused){
currentAudio.pause();
}
var audio = $('#bridget-strevens-intro')[0];
if (audio.paused) {
audio.play();
currentAudio = audio;
} else {
audio.pause();
}
});
Update:
Thanks for the prompt responses! Grimbode, I've tried what you
suggest, and that seems to work. However is there the ability to stop
and reset rather than just pause - so if they clicked on 1 then [2]
before 1 finished, then clicked 1 again, that 1 would start from
the beginning again rather than the point at which it was paused? And
is there any way of check the state 'globally', and then add code for
each individual audio file - just to keep the amount of code and
duplication down? Thanks again!! –
Yes. Play audio and restart it onclick explains in detail how to do this. The final result would look something like this:
var currentAudio = null;
$(".bridget-strevens").click(function () {
if(currentAudio != null && !currentAudio.paused && currentAudio != this){
currentAudio.pause();
//Here we reset the audio and put it back to 0.
currentAudio.currentTime = 0;
}
var audio = $('#bridget-strevens-intro')[0];
if (audio.paused) {
audio.play();
currentAudio = audio;
} else {
audio.pause();
}
});
You can't really optimize the code much more. You're going to have apply the click event on every audio element. You're going to have to keep the current playing audio element memorized so you don't have to loop through all the audio files.
If you really want to take this further you could create a library to handle everything. Here is an example:
(function(){
var _ = function(o){
if(!(this instanceof _)){
return new _(o);
}
if(typeof o === 'undefined'){
o = {};
}
//here you set attributes
this.targets = o.targets || {};
this.current = o.current || null;
};
//create fn shortcut
_.fn = _.prototype = {
init: function(){}
}
//Here you create your methods
_.fn.load = function(){
//here you load all the files in your this.targets.. meaning you load the source
//OR you add the click events on them.
//returning this for chainability
return this
};
//exporting
window._ = _;
})();
//here is how you use it
_({
targets: $('.audio')
}).load();
I have a code that works great for starting and pausing audio html5 player and it looks like this
i want to insert that the img of the player will too change on every click and what i wrote is this
<script>
function aud_play_pause4() {
var myAudio = document.getElementById("myAudio4");
if (myAudio.paused) {
myAudio.play();
} else {
myAudio.pause();
}
}
</script>
<script>
function aud_play_pause5() {
var myAudio = document.getElementById("myAudio5");
if (myAudio.paused && document.getElementById("btn").src == "btnpause.png") {
myAudio.play();
document.getElementById("btn").src = "btn.png";
} else {
myAudio.pause();
document.getElementById("btn").src = "btnpause.png";
}
}
</script>
this is the fifth track ID
im checking the log but their is nothing wrong with the code
but what I saw that it changes the first track id and not the fifth
192.185.121.126/~vagabond/coral/ this is the link
Your IDs must be specific for each button (img)... you have "btn" as the ID for all your buttons (img).
So, when you call document.getElementById("btn") it is getting the first img (button).
I've tried two different methods of toggling the play/pause button on my player, neither of which work on the first click, for some reason.
This one, supposedly checks the status of the audio to see if it's paused or ended:
function togglePlayPause() {
var audioPlayer = document.getElementsByTagName('audio')[0];
var playpause = document.getElementById("playpause");
if (audioPlayer.paused || audioPlayer.ended) {
playpause.title = "pause";
playpause.innerHTML = "pause";
}
else {
playpause.title = "play";
playpause.innerHTML = "play";
}
}
Or I've tried this one, which just toggles via the onClick toggle(this):
function toggle(obj) {
if (obj.className== 'playButton') {
obj.className = 'pauseButton';
obj.title = "PAUSE";
obj.innerHTML = "PAUSE";
} else {
obj.className = 'playButton';
obj.title = "PLAY";
obj.innerHTML = "PLAY";
}
}
Neither toggle the first time the button is clicked, although the first method does change from the default inner "PLAY" to "play", so I guess that's something:
<div title="play" class="playButton" id="playpause">PLAY</div>
In both methods, subsequent clicks work fine. Any idea why this is happening? Could it have something to do with the way the audioPlayer variable is called? The array starts from 0. (I'm clutching at straws.)
Many thanks as usual!
I would go without creating functions, I would check if the link is clicked then proceed to the events that would be fired.
so something like $("#start").click(function(){}); in can be tried.
First, have the jQuery library included in your HTML header.
Then create a new javascript file, included it as well (usually this is put after the jQuery included)
In your new javascript file write the following
$(document).ready(function() {
$("#start, #stop, #play, #pause").click(function() { //you can have more or less selectors (selectors are the ones with #)
//Your code goes here
});
});
Here is a fiddle for that solution. http://jsfiddle.net/JRRm2/1/ (tidier text: http://jsfiddle.net/JRRm2/2/)
I have this audio tag playing in the background, and I'm able to store the progress in seconds to a cookie.
But in no way I'm able to start the audio from that cookie. (for continuing on other pages)
$("p#sound audio").currentTime = $.cookie("audioTime");
<audio autoplay="autoplay" loop="loop" ontimeupdate="document.getElementById('tracktime').innerHTML = Math.floor(this.currentTime); $.cookie('audioTime', Math.floor(this.currentTime));">
<source src="audio/song.ogg" type="audio/ogg" />
<source src="audio/song.mp3" type="audio/mp3" />
Your browser does not support the audio tag.
</audio>
<span id="tracktime">0</span>
Does this have to do with the song being loaded again from start?
Thanks!
EDIT:
$("p#sound audio").get[0].currentTime
With .get[0], it doesn't work either.
Can someone please clear things up for me? Greatly appreciated!
You need to wait until audio source loads before you set the current time.
$(function(){
$('audio').bind('canplay', function(){
$(this)[0].currentTime = $.cookie('audioTime');
});
});
You can set the start time by adding t=<time> to the URL, as documented here: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_HTML5_audio_and_video#Specifying_playback_range
E.g. <audio src="http://example.com/audio.mp3#t=50></audio>
At first there is an error in your code because currentTime is not a part of jQuery (but you already know this)
$("p#sound audio").currentTime // is incorrect (refers to a property of jQuery)
$("p#sound audio")[0].currentTime // is correct (refers to a property of DOM element)
I discover that the audio tag has some strange things and can be operate differently from browser to browser, for example in Chrome.
At first you have to wait for the 'durationchange' event to be sure the length is known by the object.
After this you have to start the stream with 'play()' (if not already started) and pause it (sometimes after a short delay) with the 'pause()' function. Then you can change the 'currentTime' property with the value. After this you have to start the stream again by using the 'play()' function.
Also it is sometimes needed to load the stream by yourself by using the 'load()' function.
Something like this:
$(document).ready( function()
{
var a = $('audio:first'),
o = a[0];
a.on( 'durationchange', function(e)
{
var o = e.target;
if( o )
{
o.pause();
o.currentTime = parseInt( $.cookie("audioTime"));
o.play();
}
});
if( o )
{
o.load();
o.play();
}
});
You have to play with it to be sure what is the best in your situation, for example the resume (play again) method to delay it for a second or so.
When using this method you don't have to use the autoplay feature because most of the time it doesn't work.
Hope it helps, greetz,
Erwinus
what I found in my case is that there is an issue with context somewhere. I initialize audio under the window context but when I try to change currentTime from XMLHttpRequest response it does NOT work. I don't know the answer yet but I'm providing a clue maybe an expert in Javascript will know how to make it work.
/* initialize this.audio player */
Audio = function() {
var that = this;
// keep track of playback status
var AudioStatus = {
isPlaying : false
};
// define references to this.audio, pulldown menu, play-button, slider and time display
that.audio = document.querySelector("AUDIO");
/* load track by menu-index */
var loadTrack = function() {
if(that.audio == null){
log("audio null"); return;
}
that.audio.src = '../sounds/400.mp3';
that.audio.load();
};
/* callback to play or pause */
that._play = function() {
if(that.audio == null){
log("audio null"); return;
}
that.audio.play();
AudioStatus.isPlaying = true;
};
that._pause = function() {
if(that.audio == null){
log("audio null"); return;
}
that.audio.pause();
AudioStatus.isPlaying = false;
};
that.playPause = function() {
if (that.audio.paused) {
self._play();
}
else {
self._pause();
}
};
/* callback to set or update playback position */
that.updateProgress = function(value) {
if(that.audio == null){
log("audio null"); return;
}
that.audio.currentTime = value; // <<<--- it does NOT work if I call from XMLHttpRequest response but it DOES if it is called from a timer expired call back
};
that.isAudioPlaying = function(){
return AudioStatus.isPlaying;
};
};
This works for me.
if (!isNaN(audio.duration)) {
audio.currentTime = 0;
}
Hope it helps!
This solved it for me:
$("p#sound audio").on('loadedmetadata', () => {
$("p#sound audio").get(0).load();
});
So I could later set the currentTime without worrying about whether the audio was loaded or not.
I had a similar problem when trying to play a HLS stream through an HTML audio element.
No matter where and how I tried to set the currentTime property on the audio element, it wouldn't work until about 2.5s after calling audioElement.play().
//Calling this
htmlElement.currentTime = 5.5;
console.log('currentTime: '+htmlElement.currentTime);
//Would return 'currentTime: 0';
What did work tho, was if I called that in a timeout with 2500-3000ms delay.
After a day of debugging to pinpoint the element state in which it would allow me to set the currentTime property, so I wouldn't have to rely on a fixed timeout.
My solution was to listen to 3 HTMLMediaElement events (https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement#events): loadedmetadata, loadeddata and canplaythrough and setting custom flags when they were first reported.
When all 3 were reported and the HTMLMediaElement.duration property was bigger than 0, I set the HTMLMediaElement.currentTime to my desired value inside the first HTMLMediaElement timeupdate event callback.
This can be summed up in the following code snippet:
let audioElementStates = {
'metadataloaded': false,
'dataloaded': false,
'canplaythrough': false
};
let shouldSetOldTime = true;
let audioElement = document.getById('audio-element');
audioElement.src = 'https://somedomain.com/hlsplaylist.m3u8';
audioElement.addEventListener('loadedmetadata',()=>{audioElementStates.metadataloaded = true;});
audioElement.addEventListener('loadeddata',()=>{audioElementStates.dataloaded = true;});
audioElement.addEventListener('canplaythrough',()=>{audioElementStates.canplaythrough = true;});
audioElement.addEventListener('timeupdate',()=>{
if(shouldSetOldTime &&
audioElement.duration>0 &&
audioElementStates.metadataloaded &&
audioElementStates.dataloaded &&
audioElementStates.canplaythrough){
audioElement.currentTime = 5.5;
shouldSetOldTime=false;
}
});
audioElement.play();
For reference I was using this with Vue.js in a Quasar framework mobile app packaged with Apache Cordova.
NOTE: The loadedmetadata check can probably be skipped, since loadeddata would presumably never fire before loadedmetadata.