php jquery ajax incremental output - javascript

I have a webpage that calls an AJAX script - ajax.php. I am using JQuery to send the AJAX requests.
The script ajax.php receives some arguments via$_REQUEST, based on that it starts its processing. The processing has multiple steps involved and at the end of the each step I want to send some feedback back to the page - for example:
Step 1 completed
Step 2 completed
....
Once all the steps are completed - the script ajax.php will output a TXT file which I am outputting via:
header('Content-type: text/plain');
header('Content-Disposition: attachment; filename="output.txt"');
My questions are:
I have a div in the page where I want to show the user that Step 1 completed, Step 2 completed, ... If I use JQuery.ajax(), will the .done function called multiple times? If no, whats the best way to handle it? Can I use ob_implicit_flush in PHP to send 'Step x completed 'messages?
Finally, how will I handle the output of .txt file so that user's browser downloads it? I don't want to save the file on the server and then going into hassle of server disk space, cron jobs of deletes, etc.
I have the option of doing multiple AJAX requests - but again I don't want to do this as this will make my code logic pretty complex and I will have to save a lot of data in $_SESSION to be visible across requests which is again something that I don't want to do.

After your AJAX call to kick off your process, you could make another AJAX call in a loop which requests, returns, and presents the current percentage complete until it reaches 100%. Basically, one AJAX call to initiate the process and then a series of calls which check status.
Here is some simple JavaScript to achieve what you want:
<script>
function startProcess() {
//start your long-running process
$.ajax({
type: 'GET',
url: "/longRunningProcess",
async: true,
success:function (data) {
//do something - your long process is finished
}
});
}
function getStatus() {
//check your progress
$.ajax({
type: 'GET',
url: "/checkProgress",
async: true,
success:function (data) {
//assume the data returned in the percentage complete
var percentage = parseInt(data);
//write your status somewhere, like a jQuery progress bar?
if (percentage < 100) {
//if not complete, check again
getStatus();
}
}
});
}
</script>

Related

Wait till completion of script [ ajax ]

the below code if the ajax call i make to my run.py and then displays the output in a html tag. the script run.py runs for over 2 mins. But in the js script below. as soon as the script has begun to run. the output ( initial lines of the output) will be displayed in the html tag. the remaining part of the script won't be displayed.
$(document).ready(function(){
$(sub).click(function(){
alert("connecting to host")
$.ajax({
type:'POST',
url:'/cgi-bin/run.py',
dataType: 'html',
success:function (z) {
$('#output').html(z);
}
});
}) ;
});
I'd like to know if there is any function in ajax to wait till completion of script (Not just execution of script. but wait till end ) and then display entire output to the html tag.
Here is my python script:
import sys, os
import cgi, cgitb
def __init__(self, address, username, password):
# connects to host
def sendShell(self, command):
#opens shell
def process(self):
while self.shell.recv_ready():
info += self.shell.recv(1024)
output = str(info, "utf8")
print(output)
hostname = "z.com"
password = "yyy"
username = "dd"
connection = ssh(hostname, username, password)
connection.openShell()
connection.sendShell("date");
jQuery.ajax() has an option async: false, however I'd advise against it and just do whatever you need in ajax callbacks. Also, it's deprecated.
Changing the async flag of the $.Ajax function to false is almost correct, yet in your case the script needs to run for long time so you need to consider using Long Polling for such a request.
The reason is because the browsers have max timeout for ajax calls and usually is set to 1 min depending on the browser(so in your case after 1 min the client / browser stops the connection and wants the response, but you want it to wait until its done and only then send the response back).
So to overcome this you will have to send once a 20 sec or once of the max timeout another request to the py script to check if its done.
Code snippet for javascript side:
function isDone(timestamp) {
timestamp = timestamp || null;
$.ajax({
type:'POST',
url:'/cgi-bin/run.py',
dataType: 'json',
data: { "timestamp": timestamp },
timeout: 20000, // Or to whatever the max-timeout is, haven't checked that with jQuery.
success: function (response) {
if (response.done === false) {
isDone(Date.now ());
} else {
// got the results, can continue.
$('#output').html(response.output);
}
}
});
}
isDone();
I'm not sure how the pyton script should look like, if you want you can share it with me and I will try to complete the server side.
Basically what you should do there is to set the timeout of the script to the max, and return the correct response to the client.
JSON response should look like this:
{
"done": true, // or false if the script timed out.
"output": html, // the variable that should contain the output when the py script is done, if its not done just send a null or don't send it back to the client at all.
"timestamp": time.time() // if im not wrong that's how you get timestamp in py
}
Server-side in pseudo code:
Dynamcally or under setting, configure python script execution time to max or rather to 3 min, sense you mentioned it takes 2 min.
if (timestamp === null) { // first ajax call to this script.
- Start long processing task.
- Write the output to a file.
}
do { // check this code block every 1 sec
if (the file you are writing to was created and is complete / unlocked) {
- Read from that file the content, save it into a variable and delete the file from your system.
- Output the above mentioned response with done set to true and the current timestamp.
- Break outside of the loop
}
if (timed out) { // basically check if 20 second passed sense starting timestamp.
- Output the above mentioned response with done set to false and the current timestamp.
- Break outside of the loop.
}
sleep for 1 sec, you don't want to kill your CPU usage.
} while (true)

How to make a progress bar in AJAX using JQUERY (CodeIgniter)

Is there a way I can make a progress bar for ajax using jquery using post data (QUERIES) and not uploading a file?
Because the ProgressEvent.lengthComputable read-only property is a Boolean flag indicating if the resource concerned by the ProgressEvent has a length that can be calculated.
If not, the ProgressEvent.total property has no significant value. So my problem is I use ajax for long process queries and not for uploading file. Thanks.
Hi from what i understand, you have a long process running on server that you call using XHR, now you want to show a progress bar in the browser.
Short answer
Not possible in ajax
Long answer
Ajax is just same as http request and there is no way to know the status of the request on server . Only the final output and http status code is available.
Solution
What you want is web sockets and not ajax. WS are bi directional communication standards. On server you can keep publishing the status of the request into the web socket. On client side read from web socket and display the changes.
So overall you need a WS server. Send request from client using websocket and finally keep reading websocket for status till you get the results.
Is this complication needed
Although this is very long and tedious job i know that some projects need it if they have long tasks. Another alternative that you can have is push the task into celery and use XHR poling to get the status of the job.
Hope this helps
In an AJAX request you do not know the response duration on the time you execute the call.
A solution might be to set a timeout limit for the ajax call and animate a progress bar depending on this time. Of course the response will be available before this time limit (at least that's what we want). In this case, force the progress bar to complete it's animation and proceed with your data manipulation.
EXAMPLE
HTML
<!-- LOADER -->
<div id="loader"></div>
jQuery
/**
* Execute ajax request and initialize loader animation
* #param time {number} The ajax timeout limit and progress bar animation duration
*/
function executeAjax(time) {
// Start progress bar initialization
$('#loader').animate({ 'width', '100%' }, time);
// Execute ajax call
$.ajax({
url: '...',
method: 'POST',
data: { ... },
dataType: 'json',
success: function(data) {
// Stop previous animation and start a new one with 0.5 sec duration
$('#loader').stop().animate({ 'width', '100%' }, 500)
.queue(function() {
// Handle the response data here
$(this).dequeue();
});
},
error: function(jqXHR, errorType) {
alert('Error: ' + errorType);
},
timeout: time
});
}
// Call the function passing a timeout of 10 seconds
executeAjax(10000);

Javascript not proceeding aynchronously beyond AJAX call

When the user presses the 'Process' button on my application, I would like the application to trigger an AJAX request and then immediately redirect the user to another screen without waiting for the results of the AJAX request. I believe I have coded it appropriately but I notice that the screen is waiting for the AJAX to finish before redirecting. Am I missing something below?
$('#process-btn').on('click', function()
{
// disable the process & cancel buttons to prevent
// double submission or interruption
$('#cancel-btn').addClass('disabled');
$(this).addClass('disabled');
// trigger the AJAX require to process the uploaded file on the server side
$.ajax({
url: $('#form').attr('action'),
type: 'post',
data: $('#form').serialize(),
success: function() {
//on success
}
});
// redirect the user to view list
// this line is not being called immediately -
// this is being called only after AJAX returns
window.location.replace( www_root + 'Home/index' );
});
Because the button you have this handler hooked to is a submit button for a form (per your comments) and you aren't preventing the default behavior of that button, then the form submit will happen immediately and when the submit returns, it will change the page regardless of what your code tries to do.
So, the issue is that the returned form submit was overcoming what your code was trying to do.
You may be living a little dangerously by redirecting before your ajax call has finished. It's possible the browser could drop the ajax connection before the TCP buffers had actually been sent as TCP often has a small delay before sending buffers in order to collect consecutive data into common packets. It would be much safer to either redirect after a short timeout or redirect on the complete event which will be called regardless of ajax success.
If you really want to do the redirect BEFORE the ajax call has completed, you can experiment with the timeout value (shown here as set to 500ms) in this code to see what works reliably in multiple browsers:
$('#process-btn').on('click', function(e) {
// prevent default form post
e.preventDefault();
// disable the process & cancel buttons to prevent
// double submission or interruption
$('#cancel-btn').addClass('disabled');
$(this).addClass('disabled');
// trigger the AJAX require to process the uploaded file on the server side
$.post($('#form').attr('action'), $('#form').serialize());
// redirect the user to view list
// this being called after a short delay to "try"
// to get the form ajax call sent, but not "wait" for the server response
setTimeout(function() {
window.location.replace( www_root + 'Home/index' );
}, 500);
});
Also, note that I've added an e.preventDefault() and added the e argument to the event handler to make sure the form is not posted by default, only by your ajax code.
And, the timeout time is set here to 500ms. What you need is enough time for the TCP infrastructure in the host computer to send all your form data before you start the redirect. I see a mention of a "file upload" in your comments. If this form is actually uploading a file, that could take way, way longer than 500ms. If it's just sending a few form fields, that should go pretty quickly assuming there are no connection hiccups.
Caveat: Doing it this way is not the 100% reliable way of getting data to your server. There can easily be some conditions where it takes longer than usual just to do a DNS lookup before connecting with your server or your server could momentarily take longer to respond to the initial connection before data can be sent to it. The only 100% reliable way is to wait until the ajax call has succeeded as mentioned elsewhere.
You could perhaps have the best of both worlds (reliability + fast response) if you changed the way your server processes the ajax call so that as soon as it has received the data, it returns a successful response (e.g. in milliseconds after receiving the data) and then after it has sent back the successful response so the browser can then reliably do its redirect, it takes it's 2-3 minutes to actually process the data. Remember, you don't gave to wait until you are done processing the request to return a response. Then, you know that the server has received the data, but the browser doesn't have to wait for the processing time. If you don't always want this ajax call to work that way, you can pass an argument to the ajax call to instruct the server whether you want the fast response or not.
Why not try this:
$.ajax({
url: $('#form').attr('action'),
type: 'post',
data: $('#form').serialize(),
success: function() {window.location.replace( www_root + 'Home/index' );}
});

Ajax progress bar with a big list

I have an ajax call that is grabbing a large json list. Is there any way I can make a progress bar that gets the real value of json load (for example a status bar that says 1 out of 200 loaded)?
Right now I have a pretty basic Ajax call
function SendAjax(urlMethod, jsonData, returnFunction) {
$.ajax({
type: "GET",
contentType: "application/json; charset=utf-8",
url: urlMethod,
data: jsonData,
dataType: "json",
success: function (msg) {
if (msg != null) {
ReturnJson(msg);
}
},
error: function (xhr, status, error) {
// Boil the ASP.NET AJAX error down to JSON.
var err = eval("(" + xhr.responseText + ")");
// Display the specific error raised by the server
alert(err.Message);
}
});
}
Try using AjaxStart on your application global scope. That means you can put the code in your layout file, and if the processing is long, it will show the progress indicator...
$(document).ajaxStart(function() {
$( "#loading" ).show();
});
You can see the example and answer at preload with percentage - javascript/jquery.
there are a few states in an ajax request, but they do not represent any percentage through the request.
The network traffic should really be your real problem, you do not want to send 200 separate requests (although this would allow for a progress bar, it would make the whole request take significantly longer, depending on your network connection to the server).
You are best off just showing an activity indicator and removing it when the request completes and try to optimise your code server side to return the 200 items as fast as possible.
If 200 items really is too big (larger than X seconds to return them), you could split it in half or quarters to show some progress however this will waste time with those extra requests on network, page headers, etc.
If your server-side code has a way of sharing application state (such as the $_SESSION in PHP) you could make 2 separate requests, one that asks for the data, and one that checks on progress of the first request. Repeat the second request on a timer until the first completes, and update the $_SESSION (or whatever works in your server code) as each item is processed.
For example:
The initial page must start a session, so that the subsequent AJAX calls have the cookie, and can access the shared data:
<?php
session_start();
session_write_close(); // close the session so other scripts can access the file (doesn't end the session)
// your page content here
?>
First AJAX Call to start the processing:
<?php
function updateSession($count){
session_start(); // open the session file
$_SESSION['progress'] = $count;
session_write_close(); // let other requests access the session
}
// as you process each item, call the above function, ex:
for ($i = 1; $i <= 10; $i++) {
updateSession($i);
}
?>
Second AJAX call (repeated every X seconds) looks like:
<?php
session_start(); // open the session file
echo #$_SESSION['progress'] or 0; // echo contents or 0 if not defined
session_write_close(); // let other requests access the session
?>
Sorry I don't know ASP.NET, but hopefully the above code is useful to you.

Javascript Synchronization with JSON Requests

How can I make sure that a piece of code has executed completely before executing another? I am sending some ajax requests to a server and then using the returned data to generate the rest of the webpage. the things is, is that i need to have all that data in the webpage to proceed with the rest of the code as that code will affect what has been generated and, that code, runs before the json requests and all of that have finished... is there any way I can make sure this does not happen? I managed to solve it by performing the requests and then asking the user to press a button but that is a total no-sense way of doing it.
Any ideas?
Here is some code: The problem is that the second line is executed before the first (there are many calls to similar JSON functions).
$.getJSON(url, function(data){ $("#mycontent").append("..... stuff here...... create loads of dibs with class set to mydivclass"); });
...
$("div.mydivclass").hide();
Unforunately I cannot use the ajax synchronous property because: "dataType: "jsonp" requests do not support synchronous operations"
If you are using jQuery 1.5+ you can make use of deferreds to solve your issue:
function first_ajax_request() {
return jQuery.ajax(
// Your settings here
success: success_function_1
);
}
function second_ajax_request() {
return jQuery.ajax(
// Your settings here
success: success_function_2
);
}
function final_sucess_callback() {
// Do all your display work.
}
jQuery.when(first_ajax_request(),
second_ajax_request()).then(final_success_callback);
There is an excellent article on the topic that you should read up on as well by Eric Hynds. He gives some examples of exactly the kind of problem you are trying to solve.
jquery requests are asynchonize by default , so your code does not wait for the response , so you have no guarantee that code after request will execute after the response , so you can set the request synchronize by set the async property false , now the request is synchronize and you can gurantee the rest of the code will execute after the response from the server ,
like this .
$.ajax({
url: "page.php",
processData: false,
data: xmlDocument,,
async:false,
success: handleResponse
});

Categories