2

What I am trying to do is is use jQuery/Ajax to make a request to a PHP script and return a status update each time the foreach loop completes. I want to use the output to make a progress bar.

The problem I am having is the jQuery will only update the page once the whole script has completed. Is there a way to force either the jQuery or PHP to output on every loop and not just dump all of it on success function.

        jQuery(document).ready(function($) {            
            $(document).on('click','#fetch-snowfall-data a',function () {
              $(this).text('Fetching Snowfall Data...');
                $.ajax({
                    type: "GET",
                    async: true,
                    url: "url.php",  
                    data:{},                
                    dataType: "html", 
                    success: function(response){
                        $("#response_container").append(response);
                        $('#fetch-snowfall-data a').text('Fetch Snowfall Data');
                    }
                }); 
            return false;
            });
        });

PHP

foreach ( $results['resorts'] as $resort ) {

    //Do all the things here

    $count++;
    echo $count .'/'. $results['total_rows'];

}
9
  • Not really, you'd probably need SSE, Sockets or do polling for that, you generally can't return partial content (but it is possible with flushing) Commented Jan 5, 2016 at 18:47
  • An easy solution would be add the beforeSend: attribute and put a function that will fill your container with a spinner gif or something so at least people will see it's doing something. You would need a more sophisticated jquery: stackoverflow.com/questions/19139613/… for actual progress. Commented Jan 5, 2016 at 18:48
  • @Rasclatt I tried that earlier but I couldn't get any output from it. It doesn't detail any of the server side code, so I was not sure how to structure output Commented Jan 5, 2016 at 18:57
  • @adeneo I tried using flushing to no avail. I have been looking at SSE but have yet found a relevant example or tutorial. If you know of any please share Commented Jan 5, 2016 at 18:58
  • So the console.log(percentComplete) listed in the example didn't produce anything in your console? Commented Jan 5, 2016 at 18:59

2 Answers 2

4

Thanks everyone for all your help. I eventually managed to get this all working properly and will share exactly how I did it for anyone else's future benefit.

There are 3 files that are required - The page you are loading from, the processing script and the listening script.

You will need to know how many rows you are going to process for everything to work. I load mine from php variable $results['total_rows']; in loading.php

Loading.php

       jQuery(document).ready(function($) {
            setTimeout(getProgress,1000);
            $(document).on('click','#fetch-snowfall-data a',function () {
              $(this).text('Fetching Snowfall Data...');
                $.ajax({
                    url: 'process.php',
                    success: function(data) {
                        $("#response_container2").append(data);
                    }
                });
                setTimeout(getProgress,3000);
            return false;
            });
            function getProgress(){
                $.ajax({
                    url: 'listen.php',
                    success: function(data) {
                        if(data<=<?php echo $results['total_rows']; ?> && data>=1){
                            console.log(data);
                            $('#response_container').html('<div id="progress"><div class="progress-bar" role="progressbar" style="width:'+ (data / <?php echo $results["total_rows"] ?>)*100 +'%">'+ data + '/' +<?php echo $results["total_rows"] ?> +'</div></div>');
                            setTimeout(getProgress,1000);
                            console.log('Repeat');
                        } else {
                            $('#fetch-snowfall-data a').text('Fetch Snowfall Data');
                            console.log('End');
                        }
                    }
                });
            }
        });

Process.php

foreach ( $results['resorts'] as $resort ) { 

    //Do all the things here you want to.

    $count++;
    session_start();
    $_SESSION['progress'] = $count;
    $_SESSION['total'] = $results['total_rows'];
    session_write_close();
    sleep(1);
}

unset($_SESSION['progress']);

Listen.php

session_start();
echo (!empty($_SESSION['progress']) ? $_SESSION['progress'] : '');

if (!empty($_SESSION['progress']) && $_SESSION['progress'] >= $_SESSION['total']) {
    unset($_SESSION['progress']);
}

Some CSS for the progress bar

#progress {
    height: 20px;
    margin-bottom: 20px;
    /* overflow: hidden; */
    background-color: #f5f5f5;
    border-radius: 4px;
    -webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
    box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
}
.progress-bar {
    float: left;
    width: 0;
    height: 100%;
    font-size: 12px;
    line-height: 20px;
    color: #fff;
    text-align: center;
    background-color: #337ab7;
    -webkit-box-shadow: inset 0 -1px 0 rgba(0,0,0,.15);
    box-shadow: inset 0 -1px 0 rgba(0,0,0,.15);
    -webkit-transition: width .6s ease;
    -o-transition: width .6s ease;
    transition: width .6s ease;
}
Sign up to request clarification or add additional context in comments.

Comments

1

As suggested by adeneo, I dont think you can return partial content. I tried to research on this before with no avail. However, if anyone can correct me, i'll be very appreciative.

The end result for me is to do recursive ajax.

javascript

var data = '';
$(document).on('click','#fetch-snowfall-data a',function () {
  ajaxCall(0);
});

function ajaxCall(num) {
  $.ajax({
    type: "POST",
    async: true,
    url: "url.php",
    data: num,
    dataType: "json",
    xhr:function(){
        //progress bar information here.
    },
    success: function(response) {
      $("#response_container").append(response['data']);
      if (response['check'] === 'next') {
        var nextNum = num +1;
        data += response['data'];
        ajaxCall(nextNum); //call itself for the next iteration
      }else if (response['check'] === 'done'){
        data = response['data'];
        //do stuff with the data here.
      }else if (response['check'] === 'error') {
        return response['data'];
      }
    },
    error:function(xhr, status,error){
        //error information here
    }
  });
}

For PHP:

Just make sure you output stuff in json with two information. Json.check: to see if you want to move into the next iteration, finish and output data, or report error. Json.data to output whatever data it needs. What you need to do is output each report at a time without foreach loop

--edit--

I found some topic on streaming for php

  1. http://www.sitepoint.com/php-streaming-output-buffering-explained/
  2. Best approach for (cross-platform) real-time data streaming in PHP?

3 Comments

It is possible in coldfusion, but i'm not a php dev so no idea if it can be done with php. Look into data streaming and/or flushing the buffer.
@KevinB Thanks, i'll definitely look into it. It seems like running nodejs would be better than php?
the same can be accomplished in both, so at that point it's up to personal preference. I prefer node.js

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.