I want to display data on a webpage as it comes, let's say I have a tracert on a server and it may take longish time, but I want to show the data as it comes.
If I make it like this:
$.ajax({
url: '/cgi-bin/trace.cgi',
dataType: 'text',
async: true,
cache: false,
success: function (response) {
$('#traceOut').append(response);
}
});
it will only be called when we are done with the cgi request.
I could do it directly with XMLHttpRequest, onreadystatechange and xmlhttp.readyState==3
This works ok in Firefox but in Chrome it only dumps data as it reaches 2k.
How do I do this in jQuery?
It is possible, with polling. The tricky part will be coordinating the process for multiple users on the server side. I'll explain the workflow below.
The Method
/**
* Polls a URL until server indicates task is complete,
* then sends a final request for those results.
*
* Requires jQuery 1.4+.
*/
function poll(params) {
// offer default params
params = $.extend({
error: function(xhr, status, err) {
console.log('Network error: ' + status + ', ' + err);
},
progress: function(prog) {
console.log(prog);
},
timeoutMillis: 600000, // 10 minutes
intervalMillis: 3000 // 3 seconds
}, params);
// kickoff
_poll(params);
function _poll(params) {
$.ajax({
url: params.url,
type: 'GET',
dataType: 'json',
timeout: params.timeoutMillis,
data: 'action=poll',
success: (function(response, status, xhr) {
if ('progress' in response) {
params.progress('Progress: ' + response.progress);
}
if ('status' in response) {
if (response.status == 'pending') {
// slight delay, then poll again
// (non-recursive!)
setTimeout((function() {
_poll(params);
}), params.intervalMillis);
}
else if (response.status == 'cancelled') {
params.progress("Task was cancelled");
}
else {
params.progress("Task complete");
// done polling; get the results
$.ajax({
url: params.url,
type: 'GET',
timeout: params.timeoutMillis,
data: 'action=results',
success: params.success,
error: params.error
});
}
}
}),
error: params.error
});
}
}
Example usage
poll({
url: '/cgi-bin/trace.cgi',
progress: function(prog) {
$('body #progress').text(prog);
},
success: function(response, status, xhr) {
$('body').html(response);
}
});
Workflow
This method will send a request to the server with parameter "action" set to "poll". The CGI script should launch its background task, persist some state in the user session, and respond with JSON-formatted strings:
{"status": "pending", "progress": "0%"}
The browser will repeatedly issue these "action=poll" requests until the response indicates completion. The CGI script must keep track of the task's progress and respond to the browser accordingly. This will involve session handling and concurrency:
{"status": "pending", "progress": "25%"}
{"status": "pending", "progress": "50%"}
{"status": "pending", "progress": "75%"}
{"status": "complete"}
The browser will then issue a "action=results" request to receive the background task's final payload. In this example, it's just HTML:
"<p>The answer is: 42</p>"
Related
I want to implement a retry logic in my javascript code. This is how I'm calling the API:
$.ajax({
url: api_url + 'report',
type: 'GET',
dataType: 'json',
async: false,
tryCount : 0,
retryLimit : 3,
headers: {
"Authorization": "Basic " + btoa(api_username + ":" + api_pass)
},
data: {start: start_date, end: end_date},
success: function(result) {
data = result.results;
console.log("success");
},
error : function(xhr, textStatus, errorThrown ) {
console.log("in error");
if (textStatus == 'timeout') {
this.tryCount++;
if (this.tryCount <= this.retryLimit) {
//try again
console.log("try count:");
console.log(this.tryCount);
$.ajax(this);
return;
}
return;
}
if (xhr.status == 500) {
console.log("still 500");
} else {
console.log("still !500");
}
}
});
So when there are issues with the server and it returns http 500 then still my control in the above JS file doesn't go into the "error:" block and this line: "console.log("in error");" doesnt get printed on the console.
How can I correctly implement a retry logic in my code in case my server returns 500 then it should keep on retrying for some x amount of times?
500 error generally means that something is wrong with backend server. So it doesn't get into error block of client JavaScript. I don't think there is anything you can do. But in general you can always ask backend developers to do better error handling and return apt error response if possible.
I have a page on a project I'm developing that is attempting to make an ajax request with a specific value assigned by the button's (there are multiple) id tag. This works; the value is successfully passed and an ajax call is triggered on every click.
When I try to make the call again to the same page with a different button the variables are reassigned however the GET request that is sent remains unchanged.
How do I pass a NEW variable (in this case id) passed into the GET request?
function someAJAX(target) {
var trigger = [target.attr('id')];
console.log[trigger];
$.ajax({
// The URL for the request
url: "onyxiaMenus/menuBase.php",
// The data to send (will be converted to a query string)
data: {
//class: target.attr("class"),
tableCall: true,
sort: trigger,
sortOrder: 'DESC',
},
// Whether this is a POST or GET request
type: "GET",
// The type of data we expect back
//The available data types are text, html, xml, json, jsonp, and script.
dataType: "html",
// Code to run if the request succeeds;
// the response is passed to the function
success: function (data) {
console.log("AJAX success!");
$('#prop').replaceWith(data);
}
,
// Code to run if the request fails; the raw request and
// status codes are passed to the function
error: function (xhr, status, errorThrown) {
console.log("Sorry, there was a problem!");
console.log("Error: " + errorThrown);
console.log("Status: " + status);
console.dir(xhr);
}
,
// Code to run regardless of success or failure
complete: function (xhr, status) {
console.log("The request is complete!");
$('#view').prepend(xhr);
}
});
}
$(document).ready(function () {
$(".sort").on( "click", function (e) {
//e.stopPropagation();
//e.preventDefault();
target = $(this);
//console.log(target.attr("class"));
console.log(target.attr("id"));
/* ADD CHILDREN TO ELEMENT*/
if (target.hasClass('asc')) {
target.removeClass('asc')
} else {
target.addClass('asc')
}
/* MANAGE CLASS ADD/REMOVE FOR TARGET AND SIBLINGS */
if (target.hasClass('btn-primary')) {
} else {
target.addClass('btn-primary')
}
someAJAX(target);
target.siblings().removeClass('btn-primary');
})
});
Try to call your ajax like this someAJAX.bind(target)();
Then in function become
function someAJAX() {
$.ajax({
// The URL for the request
url: "onyxiaMenus/menuBase.php",
// The data to send (will be converted to a query string)
data: {
//class: this.attr("class"),
tableCall: true,
sort: this.attr('id'),
sortOrder: 'DESC',
},
// Whether this is a POST or GET request
type: "GET",
// The type of data we expect back
//The available data types are text, html, xml, json, jsonp, and script.
dataType: "html",
// Code to run if the request succeeds;
// the response is passed to the function
success: function (data) {
console.log("AJAX success!");
$('#prop').replaceWith(data);
}
,
// Code to run if the request fails; the raw request and
// status codes are passed to the function
error: function (xhr, status, errorThrown) {
console.log("Sorry, there was a problem!");
console.log("Error: " + errorThrown);
console.log("Status: " + status);
console.dir(xhr);
}
,
// Code to run regardless of success or failure
complete: function (xhr, status) {
console.log("The request is complete!");
$('#view').prepend(xhr);
}
});
}
trigger doesn't seem to be defined anywhere. That's the only data that would be changing between your requests as the other ones are statically coded.
You just need to make sure trigger is defined and changes between the two requests.
Thanks for the input on this problem. I got down to the bottom of my problem. My requests were being handled correctly but dumping the tables was creating syntax errors preventing the appending of new information to my page.
Thanks for the quick replies!
It wall works now.
I'm fairly new to asp.net MVC but am baffled as to why my request isn't working.
I'm trying to send an ajax request with jquery as per:
jQuery(function ($) {
var total = 0,
share = $('div.share'),
googlePlusUrl = "https://plusone.google.com/_/+1/fastbutton?url=http://bookboon.com" + $(location).attr('pathname');
setTimeout(function() {
$.ajax({
type: 'GET',
data: "smelly",
traditional: true,
url: share.data('proxy'),
success: function(junk) {
//var $junk = junk.match(regex);
console.log(junk);
},
error: function (xhr, errorText) {
console.log('Error ' + xhr.responseType);
},
});
}, 4000);
And set a line in my RouteConfig as:
routes.MapRoute(null, "services/{site}/proxy", new { controller = "Recommendations", action = "Proxy" });
The markup has a data-attribute value as:
<div class="share" data-proxy="#Url.Action("Proxy", "Recommendations")">
And my Proxy action method starts with:
public ActionResult Proxy(string junk)
The problem is that the junk parameter is always null. I can see in the debug output that the route seems to correctly redirect to this method when the page loads (as per jQuery's document ready function), but I cannot seem to send any data.
I tried sending simple data ("smelly") but I don't receive that neither.
Any suggestions appreciated!
The model binder will be looking for a parameter in the request called junk, however you're sending only a plain string. Try this:
$.ajax({
type: 'GET',
data: { junk: "smelly" }, // <- note the object here
traditional: true,
url: share.data('proxy'),
success: function(junk) {
//var $junk = junk.match(regex);
console.log(junk);
},
error: function (xhr, errorText) {
console.log('Error ' + xhr.responseType);
},
});
I'm working on a Chrome extension that's essentially a simple custom Google Form that will post to a response Spreadsheet. I got the following function to successfully send and populate data only once, but never again:
function postFormToGoogle() {
var timeOne = $("#time1hour").val();
var timeTwo = $('#time2hour').val();
var timeThree = $('#time3hour').val();
$.ajax({
url: "https://docs.google.com/forms/d/FORMKEY/formResponse",
beforeSend: function (xhr) {
xhr.setRequestHeader('Access-Control-Allow-Origin', 'chrome-extension://EXTENSION_ID');
xhr.setRequestHeader('Access-Control-Allow-Methods', 'GET, POST, PUT');
},
data: { "entry_856586387": timeOne,
"entry_244812041": timeTwo,
"entry_2138937452": timeThree },
type: "POST",
dataType: "xml",
xhrFields: {
withCredentials: true
},
statusCode: {
0: function () {
document.getElementById("message").innerHTML = "Your form has been submitted!";
window.location.replace("ThankYou.html");
},
200: function () {
document.getElementById("message").innerHTML = "Your form has been submitted!";
console.log("Success");
window.location.replace("ThankYou.html");
}
}
});
}
I had to include the cors request headers because I was getting a No 'Access-Control-Allow-Origin' warning that blocked my request.
It being an extension, I also added the following permissions to the manifest.json file:
"permissions": [
"http://docs.google.com",
"https://docs.google.com",
"https://*.google.com",
]
At this point, I'm not sure exactly what's preventing the data from posting. Possible indicators could be that when submitting the form I'm getting a "Provisional Headers are shown" caution and the server is taking way too long to respond as indicated by the Waiting (TTFB) time.
Where am I going wrong in the code? (It did work once, for some reason.) Any alternative solutions out there to post a custom form to Spreadsheets?
This is the way I did it... http://jsfiddle.net/adutu/7towwv55/1/
You can see that you receive a CORS error but it works... the data gets where it should be
function postToGoogle() {
var field3 = $('#feed').val();
$.ajax({
url: "https://docs.google.com/forms/d/[key]/formResponse",
data: {"entry.347455363": field3},
type: "POST",
dataType: "xml",
statusCode: {
0: function() {
//Success message
},
200: function() {
//Success Message
}
}
});
}
See more info here
I have following code to pull data from server. I want to call it on document.ready(). And I expect first request is made to server, get response and second request is made and so on.
But I see in Firebug, there are two request to server is being made at initial page load. I am not sure why two request.
Here is my code.
;var EVENTS = {};
;(function($) {
EVENTS.Collector = {
events: [],
getEventsData: function() {
var postData = {
'jsonrpc': '2.0',
'id': RPC.callid(),
'method': "events.getNewOrUpdated",
'params': {},
'auth': RPC.auth()
};
var events_request = $.ajax({
url: RPC.rpcurl(),
contentType: 'application/json-rpc',
type: "POST",
data: JSON.stringify(postData),
timeout: 30000
});
events_request.done(function(results) {
//console.log("Info " + results);
if (results.result.result !== null) {
if (EVENTS.Collector.events.length !== 0) {
alert(EVENTS.Collector.events.length);
} else {
alert(EVENTS.Collector.events.length);
}
}
});
events_request.fail(function(results) {
//console.error("Error " + results);
$("Error Message").insertAfter('.error');
});
events_request.always($.proxy(this.getEventsData, this));
}
};
})(jQuery);
EVENTS.Collector.getEventsData(); //function call
Thanks in advance
If you remove the code below does it call at all?
EVENTS.Collector.getEventsData(); //function call
By default ajax request are asynchronous. If you want each request to be kind of "blocking" until done, then proceed to next, you can send sync request just by adding async: false to ajax call parameters.
Give a try to the following snippet, if it's what you meant to do..??.
var events_request = $.ajax({
url: RPC.rpcurl(),
contentType: 'application/json-rpc',
type: "POST",
async: false,
data: JSON.stringify(postData),
timeout: 30000
});
Consider that sync requests causes the interpreter function pointer to wait till any result come back from the call, or till request timeout.