Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 02/18/2023 in all areas

  1. I took an alternative approach, using two data attributes for each audio player element... data-id : as above contains the track id data-play : initially 0, set to 1 when play is clicked, reset to 0 when track has ended. The play count can only be incremented if play is clicked when data-play is 0. This prevents play...pause...play...pause from boosting the count. The AJAX processing receives the id, increments pcount for that track, retrieves the new pcount, returns that in the response <?php include 'db_inc.php'; // use your own $pdo = pdoConnect('db2'); // db connection code ################################################################################ # Handle ajax requests # ################################################################################ if (isset($_POST['ajax'])) { if ($_POST['ajax']=='addPlay') { // increment the count for the selected player file $stmt = $pdo->prepare("UPDATE audio SET pcount = pcount + 1 WHERE id = ? "); $stmt->execute([ $_POST['id'] ]); // get the new count $res = $pdo->prepare("SELECT pcount FROM audio WHERE id = ? "); $res->execute([ $_POST['id'] ]); $pc = $res->fetchColumn(); exit("$pc"); // send the new count as the reponse } } ################################################################################ # get available audio files and build page output # ################################################################################ $res = $pdo->query("SELECT id , audio , pcount FROM audio "); $players = ''; foreach ($res as $row) { $players .= "<tr> <td>" . substr(basename($row['audio']), 0, -4) . "</td> <td> <audio class='player' data-id='{$row['id']}' data-play='0' controls controlsList='nodownload' src='{$row['audio']}' preload> Your browser does not support the audio element. </audio> </td> <td data-id='{$row['id']}'>{$row['pcount']} </tr> "; } ?> <!DOCTYPE html> <html lang="en"> <head> <title>sample</title> <meta charset="utf-8"> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script type='text/javascript'> $().ready(function() { $(".player").on("play", function() { let id = $(this).data("id") if ($(this).attr("data-play")=='0') { // only allow increment when data-play is 0 $.post( "", {"ajax":"addPlay", "id":id}, function(resp) { if (resp > '0') { // update the page with new play count $("td[data-id="+id+"]").html(resp) } }, "TEXT" ) $(this).attr("data-play", '1') // set data-play to 1 to prevent increments } }) $(".player").on("ended", function() { $(this).attr("data-play", '0') // now track has ended, reset data-play to 0 }) }) </script> </head> <body> <table border='1'> <tr><th>File name</th> <th>Player</th> <th>Plays to<br>date</th> </tr> <?= $players ?> </table> </body> </html>
    1 point
  2. Some Googling suggests that there's a weird and long-standing issue with the .phar such that you can't download it from a browser but need to use a tool like curl. PHP itself might work too. > php -r "copy('http://pear.php.net/go-pear.phar', 'go-pear.phar');"
    1 point
  3. So just to say it, the on event handler is accepting a callback function to run when there is a "play" event. A simpler solution would be to just have a function defined there, that the callback would run, or to define a function globally and pass the name of the function. However, @Kicken coded this function to return an anonymous function. It helps to focus in on return statements in code like this. If you notice the requestSent variable is declared outside the function declaration that does the work. This creates a "closure" (or takes advantage of javascript closure) depending on how you want to think about it. It makes the variable requestSent available to the inner function that is being returned, and this variable will continue to exist in the browser's memory associated with the window/page, until such a time as a new request is made that causes new html/javascript/css to be loaded. An alternative would be to declare requestSent globally and use that, but he gave you something more sophisticated -- a function that returns a function and takes advantage of a variable that is only visible to the anonymous function, and yet is available to the anonymous function across executions. Each time the callback is run, this could be either for the same song or a different song, so inside the function, there is a jQuery call to find the id of the button. let a_id = $(this).attr("id") It's good to think about why this is declared inside the function and how that works. Since this handler can be called for any song, the $(this) resolves in this situation as the song that is being played. Thus the a_id gets set each time there's a play event, and then gets the html id attribute. I added code to push the value onto the requestSent array, which again, since it's part of the closure for the anonymous function, survives across plays. I used Array.includes() to check if the song id already exists in requestSent. If not, I update requestSent with requestSent.push(a_id) and the ajax runs, passing a_id. The ajax is also being done using the jQuery library. The final question you should probably be asking is: if this is a function that returns a function, then how is it, that the callback, which requires a function to run, gets the actual function it needs. A function that returns a function is not a callback. The answer is that again Kicken used an IFFE here. What is actually being passed is a function that is immediately executed. You can see this because after the function definition function () { ... } It is immediately followed by the parens ie. () which causes javascript to execute the function. function () { ... }() So this code works because the function that returns a function, is run immediately, giving the callback parameter what it wants ... a function to run when a play event occurs. The function is anonymous and only bound to the event handler for play events, which also keeps global scope from being cluttered with a symbol table entry for a function that is only needed for the callback. The benefit of doing it this way is that he did not need to utilize a global variable, since closure takes care of this for you. This type of code is favored in many situations, since you don't have a slew of global variables floating around. Nothing outside the callback function can see or modify the requestSent array -- yet it is essentially a private environment that the callback uses. As I said previously -- advanced javascript stuff, that can be confusing if you are still learning javascript. Hope this helps -- using those terms (IFFE, javascript closure, js anonymous function, js callbacks, js this) will lead you to an enormous amount of additional material if you need to explore them further.
    1 point
  4. Yes, so implementing kicken's suggestion, this should work probably: $('audio').on("play", function(){ let requestSent = [] return function(){ let a_id = $(this).attr("id") if (requestSent.includes(a_id)) { return; } requestSent.push(a_id) $.ajax({ url: "count-play.php?id=" + a_id , success: function(result){ $("."+ a_id + "count").html(result) } }); }; }()); Hopefully you understand what this code does, which makes use of some tricky javascript concepts, namely: Javascript closure An IFFE
    1 point
  5. Keep track of whether or not you've sent the count request, and only send it if you haven't. $('audio').on("play", function(){ let requestSent = false return function(){ if (requestSent){ return; } requestSent = true; let a_id = $(this).attr("id"); $.ajax({ url: "count-play.php?id=" + a_id , success: function(result){ $("."+ a_id + "count").html(result); } }); }; }()); The first time the event fires, requestSent will be false so the ajax call will run and record the play event and requestSent will be set to true. Later events will see that requestSent is true and immediately return thus doing nothing.
    1 point
This leaderboard is set to New York/GMT-04:00
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.