All I need is a method that returns true if the Url is responding. Unfortunately, I'm new to jQuery and it's making my attempts at writing that method rather frustrating.
I've seen several examples of jQuery using .ajax, but the code is consistently failing on me. What's wrong?
var urlExists = function(url){
//When I call the function, code is still executing here.
$.ajax({
type: 'HEAD',
url: url,
success: function() {
return true;
},
error: function() {
return false;
}
});
//But not here...
}
That isn't how AJAX works. AJAX is fundamentally asynchronous (that's actually what the first 'A' stands for), which means rather than you call a function and it returns a value, instead you call a function and pass in a callback, and that callback will be called with the value.
(See http://en.wikipedia.org/wiki/Continuation_passing_style.)
What do you want to do after you know whether the URL is responding or not? If you intended to use this method like this:
//do stuff
var exists = urlExists(url);
//do more stuff based on the boolean value of exists
Then what you instead have to do is:
//do stuff
urlExists(url, function(exists){
//do more stuff based on the boolean value of exists
});
where urlExists() is:
function urlExists(url, callback){
$.ajax({
type: 'HEAD',
url: url,
success: function(){
callback(true);
},
error: function() {
callback(false);
}
});
}
urlExists() can not return because it needs wait for the request.
Either pass it a callback, or make it synchronous (not recommended, because it locks the browser).
var urlExists = function(url, callback) {
if ( ! $.isFunction(callback)) {
throw Error('Not a valid callback');
}
$.ajax({
type: 'HEAD',
url: url,
success: $.proxy(callback, this, true),
error: $.proxy(callback, this, false)
});
};
Then you can do
urlExists('/something', function(success) {
if (success) {
alert('Yay!');
} else {
alert('Oh no!');
}
});
It also worth mentioning the same origin policy.
Also, returning from an anonymous function's scope will not return in the parent function (like in your original example). It just returns that inner function. To return from an inner to a parent, set a flag and return it.
Basically, there is nothing wrong with your code. See it work here:
http://jsfiddle.net/PK76X/
My guess is that you're using it to check the availability of content on a different domain, which fails because browsers don't allow cross domain ajax-requests.
If the url is from the same domain as your page you can do it. But if it is from a different domain, for example google.com, then it will fail due to cross domain security.
In general, you should probably run your script in Firefox using the firebug plugin. It will give you the details needed to solve the issue.
The ajax and post methods are asynchronous, so you should handle the result in a callback method.
AJAX is basically asynchronous, and that's why the behavior you are describing.
I've used the following, which is free of cross origin, to get a simple true/false indication whether a URL is valid, in a synchronous manner:
function isValidURL(url) {
var encodedURL = encodeURIComponent(url);
var isValid = false;
$.ajax({
url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + encodedURL + "%22&format=json",
type: "get",
async: false,
dataType: "json",
success: function(data) {
isValid = data.query.results != null;
},
error: function(){
isValid = false;
}
});
return isValid;
}
The usage is then trivial:
var isValid = isValidURL("http://www.wix.com");
alert(isValid ? "Valid URL!!!" : "Damn...");
Hope this helps
Related
I have a general ajax function which I'm calling from loads of places in my code. It's pretty standard except for some extra debugging stuff I've recently added (to try to solve this issue), with a global 'ajaxworking' variable:
rideData.myAjax = function (url, type, data, successfunc) {
var dataJson = JSON.stringify(data),
thisurl = quilkinUrlBase() + url;
if (ajaxworking.length > 0) {
console.log(thisurl + ": concurrent Ajax call with: " + ajaxworking);
}
ajaxworking = thisurl;
$.ajax({
type: type,
data: dataJson,
url: thisurl,
contentType: "application/json; charset=utf-8",
dataType: "json",
async: true,
success: function (response) {
ajaxworking = '';
successfunc(response);
},
error: webRequestFailed
});
};
Now, there's one section of my code where a second ajax call is made depending on the result of the first:
getWebRides = function (date) {
var rideIDs = [];
var intdays = bleTime.toIntDays(date);
rideData.myAjax("GetRidesForDate", "POST", intdays, function (response) {
rides = response;
if (rides.length === 0) {
$('#ridelist').empty(); // this will also remove any handlers
qPopup.Alert("No rides found for " + bleTime.DateString(date));
return null;
}
$.each(rides, function (index) {
rideIDs.push(rides[index].rideID);
});
GetParticipants(rideIDs);
});
},
'GetParticipants' (which also calls 'myAjax') works fine - most of the time. But in another part of my code, 'GetWebRides' is itself called directly after another ajax call - i.e. there are 3 calls, each successive one depending on the previous. The 'top-level' call is as follows:
rideData.myAjax("SaveRide", "POST", ride, function (response) {
// if successful, response should be just a new ID
if (response.length < 5) {
// document re-arrangement code snipped here for brevity
getWebRides(date);
}
else {
qPopup.Alert(response);
}
});
so, only when there are three successive calls like this, I'm getting the 'concurrent' catch in the third one:
GetParticipants: concurrent call with GetRidesForDate
and (if allowed to proceed) this causes a nasty probem at the server with datareaders already being open. But why is this only occurring when GetParticipants is called as the third in the chain?
I see, after some research. that there are now other ways of arranging async calls, e.g. using 'Promises', but I'd like to understand what's going on here.
Solved this.
Part of the 'document re-arrangement code' that I had commented out for this post, was in fact calling another Ajax call indirectly (very indirectly, hence it took a long time to find).
I am working on the jquery to call a function to get the return value that I want to store for the variable email_number when I refresh on a page.
When I try this:
function get_emailno(emailid, mailfolder) {
$.ajax({
url: 'getemailnumber.php',
type: 'POST',
data : {
emailid: emailid,
mailfolder: mailfolder
},
success: function(data)
{
email_number = data;
}
});
return email_number;
}
I will get the return value as 6 as only when I use alert(email_number) after the email_number = data;, but I am unable to get the value outside of a function.
Here is the full code:
var email_number = '';
// check if page refreshed or reloaded
if (performance.navigation.type == 1) {
var hash = window.location.hash;
var mailfolder = hash.split('/')[0].replace('#', '');
var emailid = 'SUJmaWg4RTFRQkViS1RlUzV3K1NPdz09';
get_emailno(emailid, mailfolder);
}
function get_emailno(emailid, mailfolder) {
$.ajax({
url: 'getemailnumber.php',
type: 'POST',
data : {
emailid: emailid,
mailfolder: mailfolder
},
success: function(data)
{
email_number = data;
}
});
return email_number;
}
However, I have been researching and it stated that I would need to use callback via ajax but I have got no idea how to do this.
I have tried this and I still don't get a return value outside of the get_emailno function.
$.ajax({
url: 'getemailnumber.php',
type: 'POST',
async: true,
data : {
emailid: emailid,
mailfolder: mailfolder
},
success: function(data)
{
email_number = data;
}
});
I am getting frustrated as I am unable to find the solution so I need your help with this. What I am trying to do is I want to call on a get_emailno function to get the return value to store in the email_number variable.
Can you please show me an example how I could use a callback function on ajax to get the return value where I can be able to store the value in the email_number variable?
Thank you.
From the jquery documentation, the $.ajax() method returns a jqXHR object (this reads fully as jquery XMLHttpRequest object).
When you return data from the server in another function like this
function get_emailno(emailid, mailfolder) {
$.ajax({
// ajax settings
});
return email_number;
}
Note that $.ajax ({...}) call is asynchronous. Hence, the code within it doesn't necessarily execute before the last return statement. In other words, the $.ajax () call is deferred to execute at some time in the future, while the return statement executes immediately.
Consequently, jquery specifies that you handle (or respond to) the execution of ajax requests using callbacks and not return statements.
There are two ways you can define callbacks.
1. Define them within the jquery ajax request settings like this:
$.ajax({
// other ajax settings
success: function(data) {},
error: function() {},
complete: function() {},
});
2. Or chain the callbacks to the returned jqXHR object like this:
$.ajax({
// other ajax settings
}).done(function(data) {}).fail(function() {}).always(function() {});
The two methods are equivalent. success: is equivalent to done(), error: is equivalent to fail() and complete: is equivalent to always().
On when it is appropriate to use which function: use success: to handle the case where the returned data is what you expect; use error: if something went wrong during the request and finally use complete: when the request is finished (regardless of whether it was successful or not).
With this knowledge, you can better write your code to catch the data returned from the server at the right time.
var email_number = '';
// check if page refreshed or reloaded
if (performance.navigation.type == 1) {
var hash = window.location.hash;
var mailfolder = hash.split('/')[0].replace('#', '');
var emailid = 'SUJmaWg4RTFRQkViS1RlUzV3K1NPdz09';
get_emailno(emailid, mailfolder);
}
function get_emailno(emailid, mailfolder) {
$.ajax({
url: 'getemailnumber.php',
type: 'POST',
data : {
emailid: emailid,
mailfolder: mailfolder
},
success: function(data)
{
// sufficient to get returned data
email_number = data;
// use email_number here
alert(email_number); // alert it
console.log(email_number); // or log it
$('body').html(email_number); // or append to DOM
}
});
}
I have a JavaScript widget which provides standard extension points. One of them is the beforecreate function. It should return false to prevent an item from being created.
I've added an Ajax call into this function using jQuery:
beforecreate: function (node, targetNode, type, to) {
jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value),
function (result) {
if (result.isOk == false)
alert(result.message);
});
}
But I want to prevent my widget from creating the item, so I should return false in the mother-function, not in the callback. Is there a way to perform a synchronous AJAX request using jQuery or any other in-browser API?
From the jQuery documentation: you specify the asynchronous option to be false to get a synchronous Ajax request. Then your callback can set some data before your mother function proceeds.
Here's what your code would look like if changed as suggested:
beforecreate: function (node, targetNode, type, to) {
jQuery.ajax({
url: 'http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value),
success: function (result) {
if (result.isOk == false) alert(result.message);
},
async: false
});
}
You can put the jQuery's Ajax setup in synchronous mode by calling
jQuery.ajaxSetup({async:false});
And then perform your Ajax calls using jQuery.get( ... );
Then just turning it on again once
jQuery.ajaxSetup({async:true});
I guess it works out the same thing as suggested by #Adam, but it might be helpful to someone that does want to reconfigure their jQuery.get() or jQuery.post() to the more elaborate jQuery.ajax() syntax.
Excellent solution! I noticed when I tried to implement it that if I returned a value in the success clause, it came back as undefined. I had to store it in a variable and return that variable. This is the method I came up with:
function getWhatever() {
// strUrl is whatever URL you need to call
var strUrl = "", strReturn = "";
jQuery.ajax({
url: strUrl,
success: function(html) {
strReturn = html;
},
async:false
});
return strReturn;
}
All of these answers miss the point that doing an Ajax call with async:false will cause the browser to hang until the Ajax request completes. Using a flow control library will solve this problem without hanging up the browser. Here is an example with Frame.js:
beforecreate: function(node,targetNode,type,to) {
Frame(function(next)){
jQuery.get('http://example.com/catalog/create/', next);
});
Frame(function(next, response)){
alert(response);
next();
});
Frame.init();
}
function getURL(url){
return $.ajax({
type: "GET",
url: url,
cache: false,
async: false
}).responseText;
}
//example use
var msg=getURL("message.php");
alert(msg);
Keep in mind that if you're doing a cross-domain Ajax call (by using JSONP) - you can't do it synchronously, the async flag will be ignored by jQuery.
$.ajax({
url: "testserver.php",
dataType: 'jsonp', // jsonp
async: false //IGNORED!!
});
For JSONP-calls you could use:
Ajax-call to your own domain - and do the cross-domain call server-side
Change your code to work asynchronously
Use a "function sequencer" library like Frame.js (this answer)
Block the UI instead of blocking the execution (this answer) (my favourite way)
Note: You shouldn't use async: false due to this warning messages:
Starting with Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27), synchronous requests on the main thread have been deprecated due to the negative effects to the user experience.
Chrome even warns about this in the console:
Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
This could break your page if you are doing something like this since it could stop working any day.
If you want to do it a way that still feels like if it's synchronous but still don't block then you should use async/await and probably also some ajax that is based on promises like the new Fetch API
async function foo() {
var res = await fetch(url)
console.log(res.ok)
var json = await res.json()
console.log(json)
}
Edit
chrome is working on Disallowing sync XHR in page dismissal when the page is being navigated away or closed by the user. This involves beforeunload, unload, pagehide and visibilitychange.
if this is your use case then you might want to have a look at navigator.sendBeacon instead
It is also possible for the page to disable sync req with either http headers or iframe's allow attribute
I used the answer given by Carcione and modified it to use JSON.
function getUrlJsonSync(url){
var jqxhr = $.ajax({
type: "GET",
url: url,
dataType: 'json',
cache: false,
async: false
});
// 'async' has to be 'false' for this to work
var response = {valid: jqxhr.statusText, data: jqxhr.responseJSON};
return response;
}
function testGetUrlJsonSync()
{
var reply = getUrlJsonSync("myurl");
if (reply.valid == 'OK')
{
console.dir(reply.data);
}
else
{
alert('not valid');
}
}
I added the dataType of 'JSON' and changed the .responseText to responseJSON.
I also retrieved the status using the statusText property of the returned object. Note, that this is the status of the Ajax response, not whether the JSON is valid.
The back-end has to return the response in correct (well-formed) JSON, otherwise the returned object will be undefined.
There are two aspects to consider when answering the original question. One is telling Ajax to perform synchronously (by setting async: false) and the other is returning the response via the calling function's return statement, rather than into a callback function.
I also tried it with POST and it worked.
I changed the GET to POST and added data: postdata
function postUrlJsonSync(url, postdata){
var jqxhr = $.ajax({
type: "POST",
url: url,
data: postdata,
dataType: 'json',
cache: false,
async: false
});
// 'async' has to be 'false' for this to work
var response = {valid: jqxhr.statusText, data: jqxhr.responseJSON};
return response;
}
Note that the above code only works in the case where async is false. If you were to set async: true the returned object jqxhr would not be valid at the time the AJAX call returns, only later when the asynchronous call has finished, but that is much too late to set the response variable.
With async: false you get yourself a blocked browser.
For a non blocking synchronous solution you can use the following:
ES6/ECMAScript2015
With ES6 you can use a generator & the co library:
beforecreate: function (node, targetNode, type, to) {
co(function*(){
let result = yield jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value));
//Just use the result here
});
}
ES7
With ES7 you can just use asyc await:
beforecreate: function (node, targetNode, type, to) {
(async function(){
let result = await jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value));
//Just use the result here
})();
}
This is example:
$.ajax({
url: "test.html",
async: false
}).done(function(data) {
// Todo something..
}).fail(function(xhr) {
// Todo something..
});
Firstly we should understand when we use $.ajax and when we use $.get/$.post
When we require low level control over the ajax request such as request header settings, caching settings, synchronous settings etc.then we should go for $.ajax.
$.get/$.post: When we do not require low level control over the ajax request.Only simple get/post the data to the server.It is shorthand of
$.ajax({
url: url,
data: data,
success: success,
dataType: dataType
});
and hence we can not use other features(sync,cache etc.) with $.get/$.post.
Hence for low level control(sync,cache,etc.) over ajax request,we should go for $.ajax
$.ajax({
type: 'GET',
url: url,
data: data,
success: success,
dataType: dataType,
async:false
});
this is my simple implementation for ASYNC requests with jQuery. I hope this help anyone.
var queueUrlsForRemove = [
'http://dev-myurl.com/image/1',
'http://dev-myurl.com/image/2',
'http://dev-myurl.com/image/3',
];
var queueImagesDelete = function(){
deleteImage( queueUrlsForRemove.splice(0,1), function(){
if (queueUrlsForRemove.length > 0) {
queueImagesDelete();
}
});
}
var deleteImage = function(url, callback) {
$.ajax({
url: url,
method: 'DELETE'
}).done(function(response){
typeof(callback) == 'function' ? callback(response) : null;
});
}
queueImagesDelete();
Because XMLHttpReponse synchronous operation is deprecated I came up with the following solution that wraps XMLHttpRequest. This allows ordered AJAX queries while still being asycnronous in nature, which is very useful for single use CSRF tokens.
It is also transparent so libraries such as jQuery will operate seamlessly.
/* wrap XMLHttpRequest for synchronous operation */
var XHRQueue = [];
var _XMLHttpRequest = XMLHttpRequest;
XMLHttpRequest = function()
{
var xhr = new _XMLHttpRequest();
var _send = xhr.send;
xhr.send = function()
{
/* queue the request, and if it's the first, process it */
XHRQueue.push([this, arguments]);
if (XHRQueue.length == 1)
this.processQueue();
};
xhr.processQueue = function()
{
var call = XHRQueue[0];
var xhr = call[0];
var args = call[1];
/* you could also set a CSRF token header here */
/* send the request */
_send.apply(xhr, args);
};
xhr.addEventListener('load', function(e)
{
/* you could also retrieve a CSRF token header here */
/* remove the completed request and if there is more, trigger the next */
XHRQueue.shift();
if (XHRQueue.length)
this.processQueue();
});
return xhr;
};
Since the original question was about jQuery.get, it is worth mentioning here that (as mentioned here) one could use async: false in a $.get() but ideally avoid it since asynchronous XMLHTTPRequest is deprecated (and the browser may give a warning):
$.get({
url: url,// mandatory
data: data,
success: success,
dataType: dataType,
async:false // to make it synchronous
});
$("#container").on("change", "#control1", function() {
if ($("#checkData").val()) {
$.get("/Controller/CheckData/" + $("#control2").val(), function(data1) {
if(!data1.Success) {
alert("Unable to do POST.");
return;
});
};
formData = $("#form").serialize();
$.post("/Controller/PostData", formData, function(data2) {
// Do something...
});
}
If checkData is false, the form should post. If checkData is true, the form should only post if the get returns true.
This doesn't seem to work because the form gets posted while the alert dialog is still open. I think it may be due to the asynchronous nature of AJAX. Is this correct?
Yes. When you call the $.get() method, the code continues executing. That means that it immediately goes to the declaration and $.post() call that follow. If you want to wait to execute those until after the $.get() call completes, you'll need to put them in the callback function.
yes, the post will always happen because you haven't done anything to prevent it. If you want the post to be sent or not sent based on the outcome of the $.get, you'll need to move it to the get callback fn.
Additionally, your code was riddled with syntax errors, though I suspect many of them were copy paste errors otherwise you wouldn't have even been getting the alert.
$("#container").on("change", "#control1", function () {
if ($("#checkData").val()) {
$.get("/Controller/CheckData/" + $("#control2").val(), function (data1) {
if (!data1.Success) {
alert("Unable to do POST.");
} else {
var formData = $("#form").serialize();
$.post("/Controller/PostData", formData, function (data2) {
// Do something...
});
}
});
}
});
Yes, you'll allways get to $.post...
Yes. And you cannot return from a callback. You will need to do
$("#container").on("change", "#control1", function () {
if ($("#checkData").val()) {
var formData = $("#form").serialize();
$.get("/Controller/CheckData/" + $("#control2").val(), function (data1) {
if (!data1.Success)
alert("Unable to do POST.");
else
$.post("/Controller/PostData", formData, function (data2) {
// Do something...
});
});
}
});
Btw, it might be unsafe to rely on a client-side check of the data (even if by ajaxing /CheckData/) before "allowing" a POST request. If you want a two-step process, you should return a "safety" token from the GET request.
Please note that these two lines are reversed in your code (and therefore don't match up):
$("#container").on("change", "#control1", function() {
if ($("#checkData").val()) {
var c2 = $("#control2").val();
$.get("/Controller/CheckData/" + c2, function(data1) {
if(!data1.Success) {
alert("Unable to do POST.");
return;
} <=== HERE
}); <=== HERE
};
formData = $("#form").serialize();
$.post("/Controller/PostData", formData, function(data2) {
// Do something...
});
}
I extracted var c2 from the $.get line only to see the braces more easily, not for any other reason.
I have a javascript function called GetRequest() that calls the server with $.ajax() and receives a json string:
function GetRequest(ThePage) {
RequestedPage = parseInt(ThePageNumber,10);
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "../Pages/MyPage.aspx/GetPage",
data: "{'ThePage':'" + ThePageNumber + "'}",
dataType: "json",
success: function (msg) {
var data = msg.hasOwnProperty("d") ? msg.d : msg;
OnSucessCallBack(data);
},
error: function (xhr, status, error) {
alert(xhr.statusText);
}
});
};
I have a function called ShowData() that calls GetRequest() and must wait until GetRequest receives its data before continuing.
function ShowData() {
//some code that determines the page number
GetRequest(ThePageNumber);
//wait until the data is in
};
I use GetRequest in several places so I can't use its success function in the context of ShowData.
How do I make my function ShowData pause its execution until GetRequest is finished? I thought of changing the OnSuccessCallBack function and determine which function initially called GetRequest() but I'm not sure on how to best do this.
Thanks for your suggestions.
add a function pass-in to GetRequest like so:
function GetRequest(pageNumber, successCallback){
//I admit this isn't "elegant" but it's most assuredly readable
var callback;
if (successCallback == null) {
callback = //default callback definition here
} else {
callback = successCallback;
}
//do everything else the same here
//except use the callback defined above
}
This gives you the flexibility to add in a separate callback handler for the onsuccess
Alternately, do the same as above, but use the "onComplete" handler unless you need the data specifically on the return (it doesn't appear as tho you do).
I'm going to strenuously suggest that you do use callbacks for asynchronous code instead of trying to shoehorn in sync requests. It's much better to just adopt a coding style that revolves around async requests when working in javascript, especially where you're already doing AJAX (which is by definition intended to be async).
Pass async:false along with the ajax options..
$.ajax({
type: "POST",
async:false,
.
.
.
});
You can make your call only synchronous by using ajax prefilters:
function ShowData() {
//some code that determines the page number
$.ajaxPrefilter( function( options, originalOptions, jqXHR ) {
options.async = false;
});
GetRequest(ThePageNumber);
//wait until the data is in
};