I use Backbone.js and jQuery 1.7 in my application and I have some problems in building collection. In collection I have the method, which should return some object. I do "return" in $.ajax(...) success() function.
In this case i receive "undefined" instead of expected object. I understand, that the problem is in the "return" - it make success() function return some value. But I need getDomainZones() method do a return. How can I do it?
window.DmnList = Backbone.Collection.extend({
model: DmnItem,
localStorage: new Store("hosting.WhoIs"),
destroyAll: function (options) {
while (this.models.length > 0) {
this.models[0].destroy(options);
}
},
getDomainZones: function(){
$.ajax({
url: 'http://hosting/rest/getDomains',
type: 'GET',
dataType: 'json',
cache: 'false',
timeout: 5000,
success: function(data) {
console.log(data);
return data;//problem here
},
error: function(jqXHR, textStatus, errorThrown) {
console.log("Error[getDomainZones]: " + textStatus);
console.log(jqXHR);
},
});
}
});
"Where I should place return statement"
Nowhere. You can't return the result of an asynchronous AJAX request.
Any code that relies on the data, must be called inside the success callback.
One possibility is to have your getDomainZones method receive a function that will be called when the response is received.
getDomainZones: function( callback ){
$.ajax({
url: 'http://hosting/rest/getDomains',
type: 'GET',
dataType: 'json',
cache: 'false',
timeout: 5000,
// success: callback, // alternative if there's no other work to do.
success: function(data) {
console.log(data);
callback( data ); // invoke the function received
},
error: function(jqXHR, textStatus, errorThrown) {
console.log("Error[getDomainZones]: " + textStatus);
console.log(jqXHR);
},
});
}
So then you'd pass a function to getDomainZones, and when the response is received, getDomainZones will invoke the function you passed, passing it the data.
getDomainZones( function( d ) {
// do something with the data
console.log( d );
});
Related
This question already has answers here:
jQuery - Execute 2 functions synchronously
(2 answers)
Closed 5 years ago.
In my asp.net mvc app, I have button click that points to a javascript which calls
function OnButtonClick(s, e, startUrl, progressUrl) {
Fetch(progressUrl);
ImportUpdate(startUrl);
}
Fetch and ImportUpdate are ajax jquery to a controller action.
function Fetch(progressUrl) {
positionDate = ReportingPositionDate.GetDate().toDateString();
$.ajax({
type: 'POST',
url: "#Url.Action("BloombergFet", "ImportData")",
data: JSON.stringify({ positionDate: positionDate }),
dataType: "text",
contentType: "application/json; charset=utf-8",
beforeSend: function () { lpBloomberg.Show(); },
success: function (msg) {
ImportSuccessMessage.SetText(msg);
lpBloomberg.Hide();
lpImport.Show();
},
error: function (xhr, textStatus, errorThrown) {
lpBloomberg.Hide()
}
});
}
function ImportUpdate(progressUrl) {
positionDate = ReportingPositionDate.GetDate().toDateString();
myProgressBar.Show;
$.ajax({
type: 'POST',
url: "#Url.Action("ProcessImportRecord", "ImportData")",
data: JSON.stringify({ positionDate: positionDate }),
dataType: "text",
contentType: "application/json; charset=utf-8",
beforeSend: function () { lpImport.Show(); },
success: function (msg) {
ImportDataGridView.PerformCallback();
ImportSuccessMessage.SetVisible(true);
ImportSuccessMessage.SetText(msg);
lpImport.Hide();
},
error: function (xhr, textStatus, errorThrown) {
ImportErrorMessage.SetVisible(true);
ImportErrorMessage.SetText(xhr.statusText)
}
});
}
Currently both the methods Fetch(progressUrl) and ImportUpdate(progressUrl) are called at the same time. I want Fetch(progressUrl) to complete and then ImportUpdate to run.
How do I achieve this. Appreciate all help.
Call your second function ImportUpdate(progressUrl) in the success block of the first function Fetch(progressUrl) like so:
function Fetch(progressUrl) {
positionDate = ReportingPositionDate.GetDate().toDateString();
$.ajax({
type: 'POST',
url: "#Url.Action("BloombergFet", "ImportData")",
data: JSON.stringify({ positionDate: positionDate }),
dataType: "text",
contentType: "application/json; charset=utf-8",
beforeSend: function () { lpBloomberg.Show(); },
success: function (msg) {
ImportSuccessMessage.SetText(msg);
lpBloomberg.Hide();
lpImport.Show();
//Place call for ImportUpdate function here, like so
ImportUpdate(startUrl);
},
error: function (xhr, textStatus, errorThrown) {
lpBloomberg.Hide()
}
});
}
However, like James pointed out, if you want to call ImportUpdate after every time that Fetch is called, it makes more sense to just combine them UNLESS you call ImportUpdate independently somewhere else, when Fetch is not called first.
BTW, the callbacks Kevin B. is probably referring to are used with the jQuery .post() function, which you can use like this:
// Assign handlers immediately after making the request,
// and remember the jqxhr object for this request
var jqxhr = $.post( "example.php", function() {
alert( "success" );
})
.done(function() {
alert( "second success" );
})
.fail(function() {
alert( "error" );
})
.always(function() {
alert( "finished" );
});
// Perform other work here ...
// Set another completion function for the request above
jqxhr.always(function() {
alert( "second finished" );
});
so instead of putting your function call in the success callback of your current Fetch function you'd put it in .done callback like so:
.done(function() {
ImportUpdate(startUrl);
})
.fail(function() {
//handle errors
})
Put ImportUpdate(progressUrl) inside your success callback function for Fetch(progressUrl)
I have the following ajax, and it works fine when I get a 200, but when I get a 400 I get all sorts of extra data, is there a way to get the same data as the success for errors?
$.ajax({
type: "get",
url: getHost() + "/leaderboard/score?gameId=" + $("#gameId").val() + "&scoreId=" + $("#scoreId").val(),
dataType: "json",
success: function(data){
showOutput(data);
},
error: function(data){
showOutput(data);
}
});
function showOutput(data){
$("pre code").text(JSON.stringify(data, null, 4));
$('pre code').each(function(i, block){
hljs.highlightBlock(block);
});
}
The problem you face is that those callbacks take different parameters, for example to use complete it would be
complete: function(jqXHR, textStatus ){
showOutput(JSON.parse(jqXHR.responseText));
}
the responseText is parsed since showOutput expects an object and not a JSON string.
You need jqXHR.always(function( data|jqXHR, textStatus, jqXHR|errorThrown ) { });
Ref: http://api.jquery.com/jquery.ajax/
$.ajax({
type: "get",
url: getHost() + "/leaderboard/score?gameId=" + $("#gameId").val() + "&scoreId=" + $("#scoreId").val(),
dataType: "json",
success: function(data){
// showOutput(data);
},
error: function(data){
// showOutput(data);
}
}).always(function(data) {
showOutput(data);
});
function showOutput(data){
$("pre code").text(JSON.stringify(data, null, 4));
$('pre code').each(function(i, block){
hljs.highlightBlock(block);
});
}
Note that data may not always be available (on error, you will get back a jqXHR), so you'll need to sanitize the code otherwise the JSON.stringify could throw an exception.
I'm making a request to a php file. The response is processed in .done(function(msg){}); and .fail this works fine. But sometimes the request gets an error. I made a retry for this. The retry also works. But if the first time fails and it is successful in de 2 or 3 try my request.done doesn't fire (in firebug I can see that is was successful)
My request:
var request = $.ajax({
url: "wcf.php",
type: "POST",
dataType: "xml",
async: false,
timeout: 5000,
tryCount: 0,
retryLimit: 3,
data: { barcode: value, curPrxID: currentPrxID, timestamp: (new Date).getTime()},
error: function (xhr, ajaxOptions, thrownError) {
if (xhr.status == 500) {
alert('Server error');
}
this.tryCount++;
if (this.tryCount < this.retryLimit) {
$.ajax(this);
//return;
}
}
}) ;
And this is the .done and fail:
request.done(function(msg)
{
$(msg).find("Response").each(function()
{
// my code here
});
});
request.fail(function(jqXHR, textStatus, errorThrown)
{
$("#message").html(errorThrown);
});
The .done() and .fail() methods are part of Deferred Object which is implemented in the jqXHR object returned by $.ajax(). Callbacks which you register with them are not part of $.ajax() options so you can't pass them to another $.ajax(). In your code you are subscribing only to parent $.ajax() Deferred Object callbacks. To achieve the result you want, you should wrap entire operation in another Deferred Object and use .resolveWith()/.rejectWith() methods to pass the proper context. Also you need to remember that Deferred Object can change its state to resolved or rejected only once (in another words if it fails it can't succeed later). So the final code might look like this:
var request = $.Deferred(function(deferred) {
$.ajax({
url: 'wcf.php',
type: 'POST',
dataType: 'xml',
async: false,
timeout: 5000,
tryCount: 0,
retryLimit: 3,
data: { barcode: value, curPrxID: currentPrxID, timestamp: (new Date).getTime()},
error: function (xhr, ajaxOptions, thrownError) {
if (xhr.status == 500) {
alert('Server error');
}
this.tryCount++;
if (this.tryCount < this.retryLimit) {
$.ajax(this).done(function(data, textStatus, jqXHR) {
deferred.resolveWith(this, [data, textStatus, jqXHR]);
}).fail(function(jqXHR, textStatus, errorThrown) {
if (this.tryCount >= this.retryLimit) {
deferred.rejectWith(this, [jqXHR, textStatus, errorThrown]);
}
});
}
}
}).done(function(data, textStatus, jqXHR) {
deferred.resolveWith(this, [data, textStatus, jqXHR]);
});
}).promise();
request.done(function(msg) {
$(msg).find("Response").each(function() {
//Success code here
});
});
request.fail(function(jqXHR, textStatus, errorThrown) {
$("#message").html(errorThrown);
});
Is there a way that I can see the URL that was requested when I do an Ajax request with jQuery?
e.g.,
var some_data_object = { ...all sorts of junk... }
$.get('/someurl.php',some_data_object, function(data, textStatus, jqXHR) {
var real_url = ? # <-- How do I get this
})
How can I access the URL that jQuery actually used to make the request? Perhaps some method/property of jqHXR? I couldn't find it in the documentation.
Thanks.
Set a break point in success method, then watch
this.url
is the real url for the request.
Here is a possible solution:
Catch the ajax call before it is sent to the server by implementing the beforeSend callback function.
Save the url and the data
Report it in the error message you generate.
var url = "";
$.ajax({
url: "/Product/AddInventoryCount",
data: { productId: productId, trxDate: trxDate, description: description, reference: reference, qtyInCount: qtyInCount }, //encodeURIComponent(productName)
type: 'POST',
cache: false,
beforeSend: function (jqXHR, settings) {
url = settings.url + "?" + settings.data;
},
success: function (r) {
//Whatever
},
error: function (jqXHR, textStatus, errorThrown) {
handleError(jqXHR, textStatus, errorThrown, url);
}
});
function handleError(jqXHR, textStatus, errorThrown, url) {
//Whatever
}
Using $.ajaxPrefilter:
// Make sure we can access the original request URL from any jqXHR objects
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
jqXHR.originalRequestOptions = originalOptions;
});
$.get(
'http://www.asdf.asdf'
).fail(function(jqXHR){
console.log(jqXHR.originalRequestOptions);
// -> Object {url: "http://www.asdf.asdf", type: "get", dataType: undefined, data: undefined, success: undefined}
});
http://api.jquery.com/jQuery.ajaxPrefilter/
It seems like the ajaxSend global handler (http://api.jquery.com/ajaxSend/) provides the url in its settings parameter. You could store a mapping from the xhr object to the url in your ajaxSend callback, then in your success callback look it up given the xhr object that it provides you with.
var mappings = {};
$.ajaxSend(function(event, xhr, settings) {
mappings[xhr] = settings.url;
});
$.ajax({
url: "http://test.com",
success: function(data, textStatus, xhr) {
console.log("url = ", mappings[xhr]);
delete mappings[xhr];
}
});
This has the advantage of not having to modify each $.ajax() object.
FYI, as an addition to airbai's comment -I cannot comment inside his answer,- you can add your own data to the call and retrieve it inside the callbacks. This way you don't have to parse the URL.
In this example JSONP request I have added the variable user_id (tested with jQuery 3.2):
var request = $.ajax({
dataType: "json",
url: "http://example.com/user/" + id + "/tasks?callback=?",
user_id: id,
success: function(data) {
console.log('Success!');
console.log("User ID: " + this.user_id);
},
timeout: 2000
}).fail(function() {
console.log('Fail!');
console.log("User ID: " + this.user_id);
});
I couldn't find it in the docs either. Maybe just add it to the jqXHR object through a "proxy" wrapper like...
I haven't tested this, so you may need to call
$.param() and concat to the url. See http://api.jquery.com/jQuery.param/
var myGet = function(url, data, success) {
$.get(url, data, function(data, textStatus, jqXHR) {
jqXHR.origUrl = url; // may need to concat $.param(data) here
success(data, textStatus, jqXHR);
});
}
usage:
var some_data_object = { ...all sorts of junk... }
myGet('/someurl.php',some_data_object, function(data, textStatus, jqXHR) {
var real_url = jqXHR.origUrl;
})
I'd like to know if there is a better approach to creating re-usable ajax object for jquery.
This is my un-tested code.
var sender = {
function ajax(url, type, dataType, callback) {
$.ajax({
url: url,
type: type,
dataType: dataType,
beforeSend: function() {
onStartAjax();
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
callback.failure(XMLHttpRequest, textStatus, errorThrown);
},
success: function(data, textStatus) {
callback.success(data, textStatus);
},
complete: function (XMLHttpRequest, textStatus) {
onEndAjax();
}
});
},
function onStartAjax() {
// show loader
},
function onEndAjax() {
// hide loader
}
};
<script type="text/javascript">
var callback = {
success: function(data, textStatus) {
$('#content').html(data);
},
failure: function(XMLHttpRequest, textStatus, errorThrown) {
alert('Error making AJAX call: ' + XMLHttpRequest.statusText + ' (' + XMLHttpRequest.status + ')');
}
}
sender.ajax(url, type, dataType, callback);
</script>
You can set the basic options that you always have the same separately.
for instance if you always use the same thing here:
type: type,
dataType: dataType,
for those types, you can set them separately.
Here is how you do that type of thing:
$.ajaxSetup({
type: "POST",
contentType: "application/json; charset=utf-8",
data: "{}"
});
NOW those are set and you can simplify your individual ajax calls.
EDIT:
NOTE: Setting parameters to $.ajax override these defaults. Thus presetting “data” to an empty JSON string is safe and desired. This way, any $.ajax call that does specify a data parameter will function as expected, since the default will not be used. This helps avoid issues that can be difficult to find on a deployed site.
Here is what I did:
var ajaxclient = (function (window) {
function _do(type, url)
{
return $.ajax({
url:url,
type:type,
dataType:'json',
beforeSend: _onStartAjax
}).always(_onEndAjax);
}
function _onStartAjax()
{
console.log("starting ajax call");
}
function _onEndAjax()
{
console.log("finished ajax call");
}
return {
do:_do
}
}(this));
Example usage:
ajaxclient.do("get","http://...").done(function(data) {console.log(data);})
I'd probably go the whole hog and have an Ajax Object create.
var ajax = new MySuperAjax(url, data);
ajax.onComplete = function(){}
or similar. You seem to have a halfway between a function which has some defaults it extends with those you apss in and an object for it.