Write in the div how the data streams in

Consider an AJAX call that writes to a div:

recent_req=$.post('result.php', { d: data }, function(returnData) { $('#content').html(returnData); }); 

PHP script at result.php performs some functions that take time, about 5-20 seconds for each step. I use the PHP flush() function to get information in the browser as soon as each step starts and ends, but how can I get Javascript to write data to the div #content when it comes in?

Thanks.

EDIT: To clarify: suppose result.php looks like this and, due to limitations, can hardly be reorganized:

 <?php echo "Starting...<br />"; flush(); longOperation(); echo "Done with first long operation.<br />"; flush(); anotherLongOperation(); echo "Done with another long operation.<br />"; flush(); ?> 

How can I structure AJAX to call result.php so that echo expressions are added to the #content div when they enter? Any solution with / without jQuery is welcome. Thanks!

+8
source share
7 answers

There is a method using an iframe that you could use to achieve this.

Like other suggestions related to frames, but it does not include sessions or polls or anything else, and you do not need to display the iframe itself. It also has the advantage of running any code you want at any time in the process if you are doing something more complex with your user interface than just clicking on the text on a div (for example, you can update the progress bar).

Basically, submit the form in a hidden iFrame, then clear the javascript before this frame, which interacts with the functions in the parent iFrame.

Like this:

HTML:

 <form target="results" action="result.php" method="post"> <!-- your form --> <input type="submit" value="Go" /> </form> <iframe name="results" id="results" width="0" height="0" /> <div id="progress"></div> 

Javascript on the main page:

 function updateProgress(progress) { $("#progress").append("<div>" + progress + "</div>"); } 

result.php:

 <?php echo "<script language='javascript'>parent.updateProgress('Starting...');</script>"; flush(); longOperation(); echo "<script language='javascript'>parent.updateProgress('Done with first long operation.');</script>"; flush(); anotherLongOperation(); echo "<script language='javascript'>parent.updateProgress('Done with another long operation.');</script>"; flush(); ?> 
+5
source

You cannot “transfer” data using regular ajax calls, since you cannot force your user browser to “listen” to server requests. Your success function will only be called when processing data.

However, there is a lot of discussion about "Ajax Push" on the Internet, and apparently HTML5 has websocket objects that can be used to make your custom browser listen to server requests. The definition of the syntax is still not completely stable, so you do not want to contact it, as it may change soon.

What you can do is send the request for step 1, wait for it to return, and then send the request for step 2. This will add some overhead to your total processing time (and make it much more detailed), but it should work fine if you have only a few big steps. If your steps do not require too much processing, you should not do this (since the communication time will become longer than your "effective processing time").

EDIT: what you can also do is write, for example, the user's session. Thus, you can periodically ping the server with a request to update the status. Thus, even if you have many small steps, you will need to send requests every 10 seconds or so, which is an improvement over dispatching for each step.

+4
source

As an alternative solution, you can submit a hidden form in an iframe , as shown in the following example:

 <?php function output_data($data) { echo str_pad($data, 4096, ' ', STR_PAD_RIGHT) . "\n"; flush(); } function long_runner() { output_data(""); output_data(date("H:i:s").' - Starting...<br />'); sleep(10); output_data(date("H:i:s").' - Done with first long operation.<br />'); sleep(10); output_data(date("H:i:s").' - Done with another long operation.<br />'); return("<script>parent.task_complete()</script>"); } if (isset($_REQUEST["status"])) { die(long_runner()); } ?> <!DOCTYPE html> <html> <head> <title>Write to IFRAME as data streams in</title> <style> #myform { display: none } #frm { width: 50% } </style> <script language="javascript" type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> <script> function task_complete() { alert('Task completed'); } $(document).ready(function() { $('#starter').click(function() { $('#myform').submit(); }); }); </script> </head> <body> <form id="myform" method="get" target="frm" action="<?= $_SERVER['SCRIPT_NAME'] ?>"> <input type="hidden" name="status" value="0"> </form> <a href="#" id="starter">Start</a><br /> <iframe id="frm" name="frm" frameborder="0"></iframe> </body> </html> 
+3
source

Writing a dynamic data stream in a div:

Here we are talking. You specifically asked how to dynamically record data streams in a "div". As many have said, you can dynamically write in iframes, and we just need to take it one step further. Here is a complete solution to your problem that will return this data to your div with a maximum delay of 0.5 seconds. It can be adapted if you need a faster update.

 <!DOCTYPE html> <html> <head> <title>dynamic listener</title> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script> <script type="text/javascript"> var count; $(function(){ $('#formx').submit(function(){ setTimeout(function(){ check_div(); }, 500); count = 0; return true; }); }); function check_div() { var $iframetxt = $('#iframex').contents().text(); var $div = $('#dynamic'); if( $iframetxt != $div.text() ) { console.log('rewritten!'); $div.text( $iframetxt ); setTimeout(function(){ check_div(); }, 500); count = 0; } else { count++; if(count < 40) setTimeout(function(){ check_div(); }, 500); else console.log('timed out'); } } </script> </head> <body> <div> Form <form id="formx" action="result.php" method="post" target="iframex"> <input type="submit" /> </form> </div> <div id="dynamic"></div> <iframe id='iframex' name="iframex" style="display:none" ></iframe> </body> </html> 

1. In the submit form, streaming data is sent in an iframe.

To do this, we simply set the target attribute in the form tag to the iframe name.

2. check_div () runs every 0.5 seconds to compare the text of the #dynamic div with the text content of the iframe.

If there is a difference between them, the data is written to the div, and the timeout is called again. If there is no difference, the timeout counter is incremented. If the counter is less than 40 (40 x.5 s = 20 seconds), it again calls the timeout. If not, we assume the thread is complete.

+3
source

Here is a solution using session polling:

HTML:

 <!DOCTYPE html> <html> <body> <div id="content"></div> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> <script> var pollTimeout; function pollResult(){ $.get('poll.php', function(response) { // Update #content with partial response $('#content').html(response); pollTimeout = setTimeout(pollResult, 1000); }); } $.post('result.php', function(response) { // Result is loaded, stop polling and update content with final response clearTimeout(pollTimeout); $('#content').html(response); }); // Start polling pollResult(); </script> </body> </html> 

PHP result:

 <?php class SemiStream{ public function __construct(){ @session_start(); $_SESSION['semi_stream'] = ''; } public function write($data){ @session_start(); $_SESSION['semi_stream'] .= $data; // We have to save and close the session to be // able to read the contents of it in poll.php session_write_close(); } public function close(){ echo $_SESSION['semi_stream']; unset($_SESSION['semi_stream']); } } $stream = new SemiStream(); $stream->write("Starting...<br />"); sleep(3); $stream->write("Done with first long operation.<br />"); sleep(3); $stream->write("Done with another long operation.<br />"); $stream->close(); echo 'Done.'; 

PHP poll:

 <?php session_start(); echo $_SESSION['semi_stream']; 

This works without using PHP output buffering.

+2
source

Check out the Pusher service, it looks like it can do exactly what you want: http://pusher.com/

0
source

Perhaps the question is how to implement Push technology in the application. I suggest you look at this question, which has an excellent answer with an example.

0
source

All Articles