How to make Javascript run function synchronously [duplicate] - javascript

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)

Related

How to spy/stub with mocha/chai on ajax .fail() and .done()?

I am new to mocha/chai unit testing. I have following ajax call which is making a service call. I have added .fail() and .done() as a part of ajax call.
So I am not sure what I am missing here. Sorry if I am missing basic things here. Can someone please describe what's wrong here?
function searchAPIcall(endPointurl, method, search_headers, search_identifier) {
$.ajax({
type: method,
contentType: "application/json; charset=utf-8",
dataType: "json",
url: endPointurl,
headers: search_headers,
xhrFields: {
withCredentials: true
},
success: function success(results, xhr, XMLHttpRequest) {
successCallback();
},
error: function (xhr, textStatus, error) {
callErrorFunc();
}
}).fail(function (xhr, textStatus, errorThrown) {
callFailFunc();
}).done(function () {
callDoneFunction();
});
}
I have written following unit test:
describe.only('Testing searchdoctorAPIcall function', function () {
var testurl = 'https://abc.serve.org/getData';
beforeEach(function() {
sinon.stub($, 'ajax');
});
afterEach(function() {
$.ajax.restore();
});
it('should make an ajax call', function(done) {
searchAPIcall(testurl, "GET", {"Content-Type":"application-json;charset=utf-8",X-Id":"1da9b0c8-bb52"}, "baseSearch");
expect($.ajax.calledOnce).to.be.true;
done();
});
});
I am always getting the following error while executing unit test.
undefined is not an object (near '...} }).fail(function (xhr,...')
But When I change my searchAPIcall function and remove the .dail() and .done() unit test is passing.
function searchAPIcall(endPointurl, method, search_headers, search_identifier) {
$.ajax({
type: method,
contentType: "application/json; charset=utf-8",
dataType: "json",
url: endPointurl,
headers: search_headers,
xhrFields: {
withCredentials: true
},
success: function success(results, xhr, XMLHttpRequest) {
successCallback();
},
error: function (xhr, textStatus, error) {
callErrorFunc();
}
})
}
Now if I run the unit test then it is passing.
should make an ajax call (passed)
You need to weave the test done call into your code so that it is run after the async call and your tests finish:
function searchAPIcall(endPointurl, method, search_headers, search_identifier) {
return $.ajax({ // return the call so it can be chained
...
});
}
it('should make an ajax call', function(done) {
searchAPIcall(
testurl,
"GET",
{"Content-Type":"application-json;charset=utf-8","X-Id":"1da9b0c8-bb52"}, // Note: you are missing a " before the 'X' in this line
"baseSearch"
).done(() => {
expect($.ajax.calledOnce).to.be.true;
done();
}).fail(done); // Equivalent to: .fail(error => done(error))
});

Ajax jquery to stop running when windows is closed

All,
I am new to MVC. I have built an application where a button click performs
get market data (lengthy operation).
data message and upload to database.
This is what the JavaScript function looks like:
function OnClick(s, e) {
if (true) {
$.ajax({
type: "POST",
url: "#Url.Action("DataFileUpload", "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) {
alert(xhr)
ImportDataGridView.PerformCallback();
}
});
}
}
What is happening right now is - When users close the browser in the middle of the run, controller action is still running. I can see that in my log.
How do I make browser close to stop running my controller action DataFileUpload ?
Thanks for helping out.
you can use the abort function from the XMLHttpRequest that $.ajax() returns.
abort(). If the request has been sent already, this method will abort the request.
Something like:
var xhr;
function OnClick(s, e) {
if (true) {
xhr = $.ajax({
type: "POST",
url: "#Url.Action("DataFileUpload", "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) {
alert(xhr)
ImportDataGridView.PerformCallback();
}
});
}
}
function closeBrowser() {
xhr.abort();
}
but this will only cancel the event on the client. You should also cancel the request on the serverside.

When using AJAX global error handler, how to display the name of the java script function that throws this error

For example if I have the JS ajax get/post function
function cancelFeeReport() {
var postData = "claimId=" + $("#FeeReport_ClaimID").val() + "&page=#ViewBag.PageNumber";
$.ajax({
type: "POST",
url: '#Url.Action("Cancel", "FeeReports")',
dataType: "json",
async: false,
data: postData,
success: function (result) {
// Do something
},
complete: function () {
// Do nothing for now.
}
});
}
When an error happened in the above JS function. How to identify that cancelFeeReport() threw the error to AJAX global error handler
$(document).ajaxError(function( event, jqxhr, settings, thrownError ) {
alert('Error in ' + <functioname>);
});

Jquery Ajax Call, doesn't call Success or Error [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I return the response from an asynchronous call?
I am using Jquery Ajax to call a service to update a value.
function ChangePurpose(Vid, PurId) {
var Success = false;
$.ajax({
type: "POST",
url: "CHService.asmx/SavePurpose",
dataType: "text",
data: JSON.stringify({ Vid: Vid, PurpId: PurId }),
contentType: "application/json; charset=utf-8",
success: function (data) {
Success = true;//doesn't go here
},
error: function (textStatus, errorThrown) {
Success = false;//doesn't go here
}
});
//done after here
return Success;
}
and Service:
[WebMethod]
public string SavePurpose(int Vid, int PurpId)
{
try
{
CHData.UpdatePurpose(Vid, PurpId);
//List<IDName> abc = new List<IDName>();
//abc.Add(new IDName { Name=1, value="Success" });
return "Success";
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
the service is being called Successfully from the AJAX. Value is also being Changed. But after the Service, success: or error: functions are not being called, in this case success should have been called but it is not working.
I used firebug and found that, the success or error functions are being skipped and goes directly to return Success;
Can't seem to find what's the problem with the code.
Update:
adding async: false fixed the problem
change your code to:
function ChangePurpose(Vid, PurId) {
var Success = false;
$.ajax({
type: "POST",
url: "CHService.asmx/SavePurpose",
dataType: "text",
async: false,
data: JSON.stringify({ Vid: Vid, PurpId: PurId }),
contentType: "application/json; charset=utf-8",
success: function (data) {
Success = true;
},
error: function (textStatus, errorThrown) {
Success = false;
}
});
//done after here
return Success;
}
You can only return the values from a synchronous function. Otherwise you will have to make a callback.
So I just added async:false, to your ajax call
Update:
jquery ajax calls are asynchronous by default. So success & error functions will be called when the ajax load is complete. But your return statement will be executed just after the ajax call is started.
A better approach will be:
// callbackfn is the pointer to any function that needs to be called
function ChangePurpose(Vid, PurId, callbackfn) {
var Success = false;
$.ajax({
type: "POST",
url: "CHService.asmx/SavePurpose",
dataType: "text",
data: JSON.stringify({ Vid: Vid, PurpId: PurId }),
contentType: "application/json; charset=utf-8",
success: function (data) {
callbackfn(data)
},
error: function (textStatus, errorThrown) {
callbackfn("Error getting the data")
}
});
}
function Callback(data)
{
alert(data);
}
and call the ajax as:
// Callback is the callback-function that needs to be called when asynchronous call is complete
ChangePurpose(Vid, PurId, Callback);
Try to encapsulate the ajax call into a function and set the async option to false. Note that this option is deprecated since jQuery 1.8.
function foo() {
var myajax = $.ajax({
type: "POST",
url: "CHService.asmx/SavePurpose",
dataType: "text",
data: JSON.stringify({ Vid: Vid, PurpId: PurId }),
contentType: "application/json; charset=utf-8",
async: false, //add this
});
return myajax.responseText;
}
You can do this also:
$.ajax({
type: "POST",
url: "CHService.asmx/SavePurpose",
dataType: "text",
data: JSON.stringify({ Vid: Vid, PurpId: PurId }),
contentType: "application/json; charset=utf-8",
async: false, //add this
}).done(function ( data ) {
Success = true;
}).fail(function ( data ) {
Success = false;
});
You can read more about the jqXHR jQuery Object

Where I should place return statement

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 );
});

Categories