1

I have a loop that makes a table, and each of the rows have an audio file, the audio playing has an ID of "audio"+i to give unique ids to the different audios.

I'm making a progress bar but I need the "i" variable to determine which of the audios the progress bar should act on, if I replace "i" with a number, then it works. I just haven't found a way to get the "i" variable.

HTML/PHP where the loop and audio are:

for($i=0; $i<$count; $i++){
$res = mysqli_fetch_array($result);
echo('<tbody id="tbody">
    <tr>
    <audio id="audio'.$i.'" src="mp3/'.$res["song_artist"].'-'.$res["song_title"].'.mp3"> 
    <td><button class="playbutton" id="playbtn'.$i.'" onclick="playStop('.$i.')">▷</button></td>
    <td><img class="songimg" src="getimage.php?id='.$res["song_id"].'"/> </td>    
    <td>'.$res["song_title"].'</td>
    <td>'.$res["song_artist"].'</td>
    <td>'.$res["song_genre"].'</td>
    <td>'.$res["song_album_name"].'</td>
    </tr>
</tbody>');
}    
}

Progress bar code where I need the "i" variable:

 var progressbar = document.getElementById("progress-bar");
 progressbar.onclick = function(e) {
    var audio = document.getElementById("audio"+i);
    audio.currentTime = ((e.offsetX/progressbar.offsetWidth) * audio.duration);
    }
}       

Thank you in advance.

yksi
  • 71
  • 1
  • 6
  • PHP will run the full script every time it's called. You cannot retrieve the value from JavaScript in this way because the loop will complete every time the script is called. Have a look at this: https://stackoverflow.com/questions/39589917/show-a-progress-bar-for-downloading-files-using-xhr2-ajax/39599878 – kissumisha Feb 20 '22 at 03:27
  • its bad practice to add numbers to ids, just use a class, then traverse from the button to the elements when its clicked – Lawrence Cherone Feb 20 '22 at 03:27
  • Is your program bar code already put inside the javascript function playStop(i) ? – Ken Lee Feb 20 '22 at 05:41
  • @RobyRajuOommen This solution didn't work for me, as the j value used on the progress-bar is the latest one ran by the loop, so if count = 3, j is also = 3, which makes it so the progress-bar only works for one of the audios. – yksi Feb 20 '22 at 16:01
  • @LawrenceCherone I can't see how this would work, could you explain in a bit more depth? I'm new to this so I apologize. – yksi Feb 20 '22 at 16:05
  • @KenLee It is not, the playStop function is ran when I click the play/stop button, I want a function to change the progress of the audio when I click the progressbar, so if that function is put inside playStop() it won't run because I'm not clicking the play/stop button. – yksi Feb 20 '22 at 16:07

2 Answers2

2

One of the ways is to use a hidden field to store the value of the "i".

So in your page, add the following HTML hidden field (say I set it to have an initial value of 0 , but you may use other initial value):

<input type=hidden id=activei value="0">

Now in your function playStop(i) , add a statement to store the i value to the hidden field:

function playStop(i)
{
document.getElementById("activei").value=i;
//// other commands
}

Then , change to use

 var progressbar = document.getElementById("progress-bar");
 progressbar.onclick = function(e) {
    var audio = document.getElementById("audio"+document.getElementById("activei").value);
    audio.currentTime = ((e.offsetX/progressbar.offsetWidth) * audio.duration);
    }
}       
Ken Lee
  • 6,985
  • 3
  • 10
  • 29
0

Based on your code you already have a playStop() stop function in javascript in which you pass to it the value of i as a string. From this setup you could setup an "app level" global where that i gets stored for usage by other javascript scripts in your code.

E.g.

app = {};
app.currentI = -1;
function playStop(i) {
  app.currentI = parseInt(i);

  // the rest of code
}

...

 var progressbar = document.getElementById("progress-bar");
 progressbar.onclick = function(e) {
    if (app.currentI > -1) {
      var audio = document.getElementById("audio" + app.currentI);
      audio.currentTime = ((e.offsetX/progressbar.offsetWidth) * audio.duration);
    }
} 

Since the (e) will be the target, which you need upon it being clicked, the app.currentI is the i from the PHP side you also need to know which audio was clicked, since it's already hard-coded via your call to playStop().

There is probably a better way to do all this, but without testing it myself, this solution uses your current design approach and should work without any major tweaks.

Update: In regards to I couldn't make this work for me, maybe I miss understood, but when I tested this, it didn't work, I tried logging the value of app.currentI to see if something was wrong with it, and I got "app is not defined". -- yksi

Here's a working example. app itself in this example would be defined in the global scope.

var app = {};
app.currentI = -1;

function playStop(i) {
    app.currentI = i;
    console.log(app.currentI);
}
<!doctype html>
<html>
<head>
</head>
<body>
<button onclick="playStop(0)" type="button">Play/Stop 0</button></br>
<button onclick="playStop(1)" type="button">Play/Stop 1</button></br>
<button onclick="playStop(2)" type="button">Play/Stop 2</button></br>
<button onclick="playStop(3)" type="button">Play/Stop 3</button></br>
<button onclick="playStop(4)" type="button">Play/Stop 4</button></br>


</body>
</html>

I'm showing just the rendered html for the PHP part, but that code would have looked like as follows:

<?php
    for ($i = 0; $i < 5; $i++) {
?>
<button onclick="playStop(<?php echo $i; ?>)" type="button">Play/Stop <?php echo $i; ?></button></br>
<?php   
        
    }
?>

In this way you won't need any hidden dom variables and can store all your app level specific stuff to a javascript object, e.g. app or any other name you specify.

GetSet
  • 1,511
  • 2
  • 10
  • 13
  • I see you are not passing in `i` as a string from PHP side now, but thats of no-consequence. The javascript side with the above code will handle it correctly either way. – GetSet Feb 20 '22 at 15:45
  • 1
    I couldn't make this work for me, maybe I miss understood, but when I tested this, it didn't work, I tried logging the value of app.currentI to see if something was wrong with it, and I got "app is not defined" – yksi Feb 20 '22 at 16:16