3

I am displaying some real time data from a MySQL database using PHP and JavaScript. Everything works as expected and the data is displaying as I want.

However, I would now like to implement two simple buttons to achieve the following;

  • stop - pause the current real time feed
  • start - resume the feed from where it was paused

I can get the stop button to work by using the EventSource close() function. I'm not so sure about how to resume from where I left off though. I think I may need to include the Last-Event-ID as described here.

My code so far is;

PHP

<?php 
session_start(); 
include 'conn.php'; // database connection
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
header("Access-Control-Allow-Origin: *");

$query = "SELECT TimeStamp, CardNo, SerialNo FROM transactions ORDER BY TimeStamp DESC LIMIT 1";
$stmt = $conn->prepare($query);
$stmt->execute();
$result = $stmt->get_result();

if($row = $result->fetch_assoc()) {
    echo "retry: 100\n\n"; 
    if ($_SESSION["lastSerialNo"] != $row["SerialNo"]) {
        $_SESSION["lastSerialNo"] = $row["SerialNo"];
        echo "data: ".$row['SerialNo']. ' ' .$row['TimeStamp']. "\n\n";
        flush();
    }
    else {
        // do nothing
    }
}

JS & HTML

<script type="text/javascript">
    var source = new EventSource("data.php");
    window.onload = function() {
        source.onmessage = function(event){
            document.getElementById("result").innerHTML += "Data : " + event.data + "<br>";
        };
    };

    function stop() {
        source.close(); // this successfully stops the feed
        };

    function start() {
        // how to resume the feed?
        };  

    </script>

<button id="stop" onclick="stop()"> stop</button>
<button id="start" onclick="start()"> start</button>

Any help is appreciated.

TheOrdinaryGeek
  • 2,273
  • 5
  • 21
  • 47
  • 2
    use a hidden html element or input element, change its html content/value upon clicks of buttons, and use that value in a condition to determine wether your javascript to update the real time data executes or not. – coderodour Aug 10 '17 at 15:28
  • It would seem a good idea to have an id sent as the response from the server so your javascript code can keep track of that id for later use. The only issue with using SSE like this is that the data retrieved will be relevant to each user only ( ie: one user will see a different set of dat to another depending upon when he/she opened the page/connection ) ~ websockets would provide the communication channels both ways which you need and everyone would see the same data – Professor Abronsius Aug 10 '17 at 15:32
  • could you provide an example @coderodour Thanks – TheOrdinaryGeek Aug 14 '17 at 11:30

1 Answers1

1

When the PHP script returns data from the database, get it to return the ID (primary key) of the row it's sent back.

In Javascript you can write that to a hidden element each time you get a response.

When the user clicks "stop" it will stop updating that element, because nothing is being returned from the database.

When they click "start" read the element in the hidden div and add 1 to it (assuming the ID's are auto increment). Your next database query gets records from that point, etc.

Assume there's a hidden div with the ID #hiddenDiv

window.onload = function() {
    source.onmessage = function(event){
        // what you already had goes above
        document.getElementById("hiddenDiv").innerHTML = event.id;
    };
};

Each time you get data back from your PHP script it's writing event.id (the ID from the database) to the hidden div.

Then when they click "start" you read that value:

var lastRecord = document.getElementById("hiddenDiv").innerHTML;

And in your ajax request you would have to pass in lastRecord + 1 (you may need to cast that as an int, not sure exact syntax here).

Now in your query you SELECT records WHERE id = the ID you sent in the ajax request.

Your SQL query may need adjusting a bit because all it's doing at the moment is getting 1 record (the most recent one). If they press "stop" and there are say 13 more records to show, you'll have to handle that scenario. It may be possible to return all 13, or queue them, depending on what needs to be shown in the UI.

Another solution would be as described but use the TimeStamp field that you are already getting and write that to the div, instead of the row ID. Again, you adjust your SELECT query so it gets anything where TimeStamp > the timestamp from the hidden div.

Andy
  • 5,142
  • 11
  • 58
  • 131
  • @TheOrdinaryGeek you're welcome, and glad it's helped. I come from a jquery background and personally would use jquery to make the ajax request (it's far easier than plain js, in my opinion). But essentially all you do is pass the value (`lastRecord`) and give it a name, e.g. `lastRecord:`. This means that you can refer to it in your PHP script (e.g. `$_POST['lastRecord']`). You'd have to look up the plain JavaScript syntax, but that's the principle. – Andy Aug 11 '17 at 11:32