3

I have a series of buttons on a page that when a user clicks on them they trigger a PHP script via jQuery .ajax(). Currently, I append a concatenated string dump of "progress updates" to a status placeholder DIV via the success: function(data) { $('#divplaceholder').append(data); ...} parameter. My problem is I would like to print real-time progress updates to that placeholder DIV as the execution "echoes" them.

I have read many SSE examples, tutorials, done extensive googling and I think I have an idea on how to send the "messages" back from the server but I have been unable to find an example on how to actually trigger tasker.php via jQuery to send the updates back when the user actually pushes the button. Currently my .ajax() call is being triggered by a jQuery .on('click') event.

I'm getting lost and confused between learning to send the updates back via SSE and how to trigger the execution of tasker.php (and in some cases sending parameters to it, like .ajax() enables me to do).

Any help clearing this out would be appreciated.

UPDATE #2: Found this example but as soon as the JavaScript loads it is triggered; I want to trigger execution when the button is clicked.

UPDATE #1: TO ADD SAMPLE CODE (Please excuse the formatting, I'm posting this from the mobile App) This is an abstract it of how I have it implemented right now:

<? php
$output ="";
/*dummy code*/
read_csv_file();
$output.= "Opened and read file<br/>"; //Step 1
parse_csv_file();
$output.= "CSV file successfully parsed"; //Step 2
delete_from_directory();
$output.= "CSV file successfully deleted"; //Step 3
insert_data_into_db();
$output.=  "successfully inserted records into Database"; //Step 4

return $output;
?>


<div id="placeholder"></div>
<button id="button">Update</button>


//jQuery...

$('#button').on('click', function(){
.ajax({
url: 'tasker.php',
dataType: 'txt',
data:  dataVariable,
success: function (data){
$('#placeholder').append(data);
});
});

//jQuery...
JESTech
  • 145
  • 2
  • 15
  • What about wrapping your code inside the .on('click') with a setInterval(function(){ alert("Hello"); }, 3000); – Agu V May 09 '16 at 16:24
  • It'd be useful to see some of your code. Do you mean you already have it working (i.e. but without progress updates) with `.ajax()`; what does that call look like? – Darren Cook May 09 '16 at 16:44
  • @DarrenCook done. hope it helps. thanks! – JESTech May 09 '16 at 19:55
  • wouldn't changing `$('#placeholder').append();` to `$('#placeholder').append(data);` solve this? – imvain2 May 09 '16 at 19:58
  • @imvain2 that's a typo; that's how it is right now in fact. just fixed it. but that dumps the whole string at once. what I want is to output each step as it is completed at runtime instead of having to wait til the "return". – JESTech May 09 '16 at 20:03
  • I think you will need 4 ajax calls for every step. Also if you are uploading a file you can display progress with event.loaded and event.total – Covik May 09 '16 at 20:07
  • @Covik I think the solution is SSE but I really don't understand the concept well enough to implement it correctly :( – JESTech May 09 '16 at 21:09
  • Thanks; if no-one else answers in the meatime, I'll try to post an answer tomorrow showing how SSE can be used. (**But**, is there much data in `dataVariable` ? SSE does not support POST, so it has to be short enough for GET, or you need to send the data first, then start SSE.) – Darren Cook May 09 '16 at 21:19
  • @DarrenCook I'm currently passing one parameter. Thanks for your help! – JESTech May 09 '16 at 21:20
  • So i googled php server sent events and found this: http://www.w3schools.com/html/html5_serversentevents.asp – Covik May 09 '16 at 21:21
  • @DarrenCook hi! Any chance you might be able to post your thoughts about this question anytime soon? Looking forward to your opinion. Highly appreciated. :) – JESTech May 12 '16 at 11:36
  • Sorry for the delay, finally posted an answer. (I've not checked this code, so let me know if it doesn't work: it is a bit late here, and I might have a typo.) :-) – Darren Cook May 12 '16 at 21:41

1 Answers1

0

First, on the client-side:

var server = null;
$('#button').on('click', function(){
  if(server)server.close();
  server = new EventSource('tasker.php?x=123');
  server.addEventListener('message', function(e){
    process(e.data);
    if(e.data >= 100){server.close();server=null;} //6
    }, false);
  });

Points:

  • You have to pass the parameter with GET
  • I've assumed a process() that will take your progress updates, and alter the web browser display, somehow.
  • If the button is pressed again, it closes any previous SSE connection, and starts a new one.
  • 6: see #6 on the back-end code below

On the back-end, PHP pseudo-code:

<?php
//Process inputs here
//If using sessions close them here
$lastProgress = 0;
while(true){
  $progress = ...  //1
  if($progress == $lastProgress)continue; //2
  echo "data:$progress\n\n";  //3, 4
  @ob_flush();flush();  //5
  //if($progress >= 100)exit;  //6
  }

Points:

  • 1: Get the progress (e.g. look at log file, poll a DB, etc.)
  • 2: Don't waste bandwidth; only send back new progress
  • 3: I'm assuming $progress can only be a number. If any chance it can be text, you need error-checking, or json-escaping!!
  • 4: "data:" prefix, "\n\n" is the SSE protocol.
  • 5: The PHP idiom to be sure it gets sent immediately.
  • 6: An SSE back-end is an infinite loop: the whole PHP process gets killed by Apache when the browser closes the socket. With a progress meter, you want it to die once we know there will be no more progress, but this has to come from the client (if the server disconnects, the browser will think the socket died and will try to reconnect). That is why this line is commented out. See #6 in the client code.

As a final note, you could stick with Ajax, and listen to readyState 3 (also known as the comet technique). (That is how you make it work on browsers like IE11 and earlier; also the only way to be able to use POST.)(See my book, Data Push Apps With HTML5 SSE, for loads more on those topics.)

Darren Cook
  • 27,837
  • 13
  • 117
  • 217
  • Great! I'll give it a try. About point 3, I was thinking about sending back text messages like "completed parsing", "inserting into DB", "finished executing", etc instead of a number for percentage. Also, not sure I understand what you mean about "If using sessions close them here". I have a login system and I do have session variables; not what happens if that's what you mean. Thanks for your help! – JESTech May 13 '16 at 13:28
  • Update: Thanks for taking time to answer my question. Haven't had a chance to try to implement this yet. I'll keep you informed. – JESTech May 17 '16 at 13:24