blocking javascript execution until response is completed [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
i have js code which returns rows of data for my table. On clicking each of those rows they expand and plan is to show child data of that row by calling another ajax request.
My code for child data looks like below:
function format ( d ) {
var results;
$.ajax({ url: 'http://127.0.0.1:7101/MUDRESTService/rest/v1/feedbacks/' +
d.FeedbackId + '/child/MudFeedbackDetailsVO?onlyData=true',
type: 'get',
dataType: 'json',
success: function(output) {
 console.log(output.items[0].CriticalPath) ;
results = output.items[0];
}
});
return results.CriticalPath;
}
The problem probably is that method doesn't finish by the time value of results.CriticalPath is returned. I can see value in chrome js console so there is no problem with the data part.
So how should i make it return the value once the response is ready

When writing asynchronous code, you need to start working with callbacks rather than return values.
Your functions, like format here, only initiates an action. Updates to the UI are initiated by the callback.
Instead of this logic:
function doSomething() {
var result = format(d);
doSomethingWithResult(result);
}
You need to adapt to this:
function doSomething() {
var result = format(d, doSomethingWithResult);
}
function format( d, callback ) {
$.ajax(..., {
success : function(output) {
var results = output.items[0];
callback(results); // this is where we call doSomethingWithResult
}
});
}

Now I'm no exert at this, but hopefully you'll find something from the code-example that you can use.
I'm binding each row on the .done()-function, which calls another api. I hope this helps.
JS-FIDDLE
(function(){
//getJSON example
var jqxhr = $.getJSON( "https://api.myjson.com/bins/2emll", function(data) {
for (key in data) {
$("#list").append("<li class='" + key + "'>" + data[key] + "</li>");
}
}).done(function( data ) {
$("#list li").on("click", function(e){
var target = e.target.className;
//ajax example
$.ajax({
url: 'https://api.myjson.com/bins/309x5',
type: 'get',
data: target,
dataType: 'json',
success: function(data) {
var title = $("." + target).text();
$("." + target).html(title + '<ul id="ul-' + target + '"></ul>');
}
}).done(function(data){
for (key in data) {
$("#ul-" + target).append("<li class='" + key + "'>" + data[key] + "</li>");
}
});
});
});
})();

you can try setting async option to false
like this
function format ( d )
{
var results;
$.ajax({
url: 'http://127.0.0.1:7101/MUDRESTService/rest/v1/feedbacks/' + d.FeedbackId + '/child/MudFeedbackDetailsVO?onlyData=true',
type: 'get',
dataType: 'json',
async:false,
success: function(output)
{
console.log(output.items[0].CriticalPath) ;
results = output.items[0];
}
});
return results.CriticalPath;
}
NOTE :
but it will make your ajax as synchronous and it may be possible that your browser will be unresponsive for the request so there are some points to be noted before using it
By default, all requests are sent asynchronously (i.e. this is set to true by default). If you need synchronous requests, set this option to false. Cross-domain requests and dataType: "jsonp" requests do not support synchronous operation. Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active. As of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated; you must use the success/error/complete callback options instead of the corresponding methods of the jqXHR object such as jqXHR.done() or the deprecated jqXHR.success().
The first letter in Ajax stands for "asynchronous," meaning that the operation occurs in parallel and the order of completion is not guaranteed. The async option to $.ajax() defaults to true, indicating that code execution can continue after the request is made. Setting this option to false (and thus making the call no longer asynchronous) is strongly discouraged, as it can cause the browser to become unresponsive.
fore more information you can read here

Related

Why is my Ajax callback being processed too soon?

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).

jquery synchronous ajax only appends to html at end of loop [duplicate]

This question already has an answer here:
How to get jquery to append output immediately after each ajax call in a loop
(1 answer)
Closed 4 years ago.
I need to run a php script multiple times but with a unique ID.
The script takes +- 5seconds to run each time ( downloads some files to server etc .. )
First i did this with an ajax call, but the problem was that this needs to be in sequential order, and with the default ajax settings multiple instances were run at the same time giving strange things.
I changed the parameter 'async' to 'false' which fixed the issue as now the javascript waits for the script to finish before starting the next iteration.
Console alerts pop up every 5-6 seconds and I alert back the data from each post and the loop waits for me to click the alert( good ).
Instead of alerting i try to append the data to a div, it only appends after all iterations have been done.
why?
var arr = ["10","20","30"];
$("button").click(function(){
$.each(arr, function( index, value ) {
console.log( index + ": " + value );
$.ajax({
url: "import_xml_single_post.php",
type: "post",
data: {'import_id' : value},
async: false,
success: function(data){
$( "#result" ).append( data );
//alert(data);
}
});
});
<body>
<button>Click me</button>
<div id="result"></div>
</body>
This is because the browser's UI thread is hogged by the ajax requests, so the browser doesn't have a chance to repaint the page. That's one of the reasons why synchronous ajax is something to avoid using.
There's no need for those requests to be synchronous. If you want them done in series (not in parallel), just fire of a subsequent request when you finish the previous one:
var arr = ["10", "20", "30"];
$("button").click(function() {
var index = 0;
// Start the process
doOne();
function doOne() {
// Get this value
var value = arr[index++];
console.log(index + ": " + value);
$.ajax({
url: "import_xml_single_post.php",
type: "post",
data: {
'import_id': value
},
success: function(data) {
$("#result").append(data);
},
complete: function() {
// Kick off the next request
if (index < arr.length) {
doOne();
}
}
});
}
});
In an cutting-edge environment (or with transpilation), you could use an async function so you could write synchronous-looking code that runs asynchronously:
var arr = ["10", "20", "30"];
$("button").click(async function() {
// ---------------^^^^^
try {
for (const value of arr) {
console.log(value);
await $.ajax({
// -----^^^^^^
url: "import_xml_single_post.php",
type: "post",
data: {
'import_id': value
},
success: function(data) {
$("#result").append(data);
}
});
}
} catch (e) {
// Handle/report error doing request
}
});
It's very important that you have a try/catch around the entire body of the function, because otherwise an error in the ajax call will not be handled (since nothing in jQuery is going to do anything with the promise the async function returns).

Convert function to synchronous from asynchronous [duplicate]

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

Parallel Ajax Calls in Javascript/jQuery

I am completely new to Javascript/jquery world and need some help. Right now, I am writing one html page where I have to make 5 different Ajax calls to get the data to plot graphs. Right now, I am calling these 5 ajax calls like this:
$(document).ready(function() {
area0Obj = $.parseJSON($.ajax({
url : url0,
async : false,
dataType : 'json'
}).responseText);
area1Obj = $.parseJSON($.ajax({
url : url1,
async : false,
dataType : 'json'
}).responseText);
.
.
.
area4Obj = $.parseJSON($.ajax({
url : url4,
async : false,
dataType : 'json'
}).responseText);
// some code for generating graphs
)} // closing the document ready function
My problem is that in above scenario, all the ajax calls are going serially. That is, after 1 call is complete 2 starts, when 2 completes 3 starts and so on .. Each Ajax call is taking roughly around 5 - 6 sec to get the data, which makes the over all page to be loaded in around 30 sec.
I tried making the async type as true but in that case I dont get the data immediately to plot the graph which defeats my purpose.
My question is:
How can I make these calls parallel, so that I start getting all this data parallely and my page could be loaded in less time?
Thanks in advance.
Using jQuery.when (deferreds):
$.when( $.ajax("/req1"), $.ajax("/req2"), $.ajax("/req3") ).then(function(resp1, resp2, resp3){
// plot graph using data from resp1, resp2 & resp3
});
callback function only called when all 3 ajax calls are completed.
You can't do that using async: false - the code executes synchronously, as you already know (i.e. an operation won't start until the previous one has finished).
You will want to set async: true (or just omit it - by default it's true). Then define a callback function for each AJAX call. Inside each callback, add the received data to an array. Then, check whether all the data has been loaded (arrayOfJsonObjects.length == 5). If it has, call a function to do whatever you want with the data.
Let's try to do it in this way:
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
var area0Obj = {responseText:''};
var area1Obj = {responseText:''};
var area2Obj = {responseText:''};
var url0 = 'http://someurl/url0/';
var url1 = 'http://someurl/url1/';
var url2 = 'http://someurl/url2/';
var getData = function(someURL, place) {
$.ajax({
type : 'POST',
dataType : 'json',
url : someURL,
success : function(data) {
place.responseText = data;
console.log(place);
}
});
}
getData(url0, area0Obj);
getData(url1, area1Obj);
getData(url2, area2Obj);
});
</script>
if server side will be smth. like this:
public function url0() {
$answer = array(
array('smth' => 1, 'ope' => 'one'),
array('smth' => 8, 'ope' => 'two'),
array('smth' => 5, 'ope' => 'three')
);
die(json_encode($answer));
}
public function url1() {
$answer = array('one','two','three');
die(json_encode($answer));
}
public function url2() {
$answer = 'one ,two, three';
die(json_encode($answer));
}
So there, as you can see, created one function getData() for getting data from server and than it called 3 times. Results will be received in asynchronous way so, for example, first can get answer for third call and last for first call.
Console answer will be:
[{"smth":1,"ope":"one"},{"smth":8,"ope":"two"},{"smth":5,"ope":"three"}]
["one","two","three"]
"one ,two, three"
PS. please read this: http://api.jquery.com/jQuery.ajax/ there you can clearly see info about async. There default async param value = true.
By default, all requests are sent asynchronously (i.e. this is set to true by default). If you need synchronous requests, set this option to false. Cross-domain requests and dataType: "jsonp" requests do not support synchronous operation. Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active...
The following worked for me - I had multiple ajax calls with the need to pass a serialised object:
var args1 = {
"table": "users",
"order": " ORDER BY id DESC ",
"local_domain":""
}
var args2 = {
"table": "parts",
"order": " ORDER BY date DESC ",
"local_domain":""
}
$.when(
$.ajax({
url: args1.local_domain + '/my/restful',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
type: "POST",
dataType : "json",
contentType: "application/json; charset=utf-8",
data : JSON.stringify(args1),
error: function(err1) {
alert('(Call 1)An error just happened...' + JSON.stringify(err1));
}
}),
$.ajax({
url: args2.local_domain + '/my/restful',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
type: "POST",
dataType : "json",
contentType: "application/json; charset=utf-8",
data : JSON.stringify(args2),
error: function(err2) {
calert('(Call 2)An error just happened...' + JSON.stringify(err2));
}
})
).then(function( data1, data2 ) {
data1 = cleanDataString(data1);
data2 = cleanDataString(data2);
data1.forEach(function(e){
console.log("ids" + e.id)
});
data2.forEach(function(e){
console.log("dates" + e.date)
});
})
function cleanDataString(data){
data = decodeURIComponent(data);
// next if statement was only used because I got additional object on the back of my JSON object
// parsed it out while serialised and then added back closing 2 brackets
if(data !== undefined && data.toString().includes('}],success,')){
temp = data.toString().split('}],success,');
data = temp[0] + '}]';
}
data = JSON.parse(data);
return data; // return parsed object
}
In jQuery.ajax you should provide a callback method as below:
j.ajax({
url : url0,
async : true,
dataType : 'json',
success:function(data){
console.log(data);
}
}
or you can directly use
jQuery.getJSON(url0, function(data){
console.log(data);
});
reference
You won't be able to handle it like your example. Setting to async uses another thread to make the request on and lets your application continue.
In this case you should utilize a new function that will plot an area out, then use the callback functions of the ajax request to pass the data to that function.
For example:
$(document).ready(function() {
function plotArea(data, status, jqXHR) {
// access the graph object and apply the data.
var area_data = $.parseJSON(data);
}
$.ajax({
url : url0,
async : false,
dataType : 'json',
success: poltArea
});
$.ajax({
url : url1,
async : false,
dataType : 'json',
success: poltArea
});
$.ajax({
url : url4,
async : false,
dataType : 'json',
success: poltArea
});
// some code for generating graphs
}); // closing the document ready function
It looks like you need to dispatch your request asynchronously and define a callback function to get the response.
The way you did, it'll wait until the variable is successfully assigned (meaning: the response has just arrived) until it proceeds to dispatch the next request. Just use something like this.
$.ajax({
url: url,
dataType: 'json',
data: data,
success: function(data) {
area0Obj = data;
}
});
This should do the trick.
Here's a solution to your issue: http://jsfiddle.net/YZuD9/
you may combine all the functionality of the different ajax functions into 1 ajax function, or from 1 ajax function, call the other functions (they would be private/controller side in this case) and then return the result. Ajax calls do stall a bit, so minimizing them is the way to go.
you can also make the ajax functions asynchronous (which then would behave like normal functions), then you can render the graph at the end, after all the functions return their data.

Scoping Issues inside jQuery.ajax()

I'm caching label strings by saving them into a variable, but running into weird scoping issues. I know this has to do with closures, but I can't seem to figure out what the issue is exactly.
info_lbl = {};
$("#chkCorporateGift").click(function(){
var type = $(this).is(":checked") ? "Corporate" : "Personal";
if(!info_lbl.hasOwnProperty(type)){
$.ajax({
url: svc_og + "Get" + type + "InformationLabel",
success: function(data){
info_lbl[type] = data;
}
});
}
$("#lblInformationType").text(info_lbl[type]);
});
lblInformationType label isn't set the very first time GetCorporateInformationLabel or GetPersonalInformationLabel methods are called. After the first time each one is called, the label's value is being changed. Could somebody please explain why this behavior occurs? When I use Firebug and set a break point on $("#lblInformationType").text(info_lbl[type]);, info_lbl[type] contains the right value and everything works fine on the first two calls as well.
AJAX calls are asynchronous. This means that any code following the request does not wait for the request to return before it runs.
In other words, the AJAX request does not block execution of subsequent lines of code. So by the time the response is received from the AJAX request, the following lines of code have already executed.
Any code that relies on the response of the AJAX request should be placed inside the callback.
$("#chkCorporateGift").click(function(){
// var type = $(this).is(":checked") ? "Corporate" : "Personal";
// It is more efficient to use this.checked instead of using .is(":checked")
var type = this.checked ? "Corporate" : "Personal";
if(!info_lbl.hasOwnProperty(type)){
$.ajax({
url: svc_og + "Get" + type + "InformationLabel",
success: function(data){
info_lbl[type] = data;
// code that relies on the response needs to be placed in
// a callback (or in a function that is called here).
$("#lblInformationType").text(info_lbl[type]);
}
});
} else {
$("#lblInformationType").text(info_lbl[type]);
}
});
I would image that the reason things work properly when you have a breakpoint is that the pause in execution gives the AJAX response time to return.
EDIT: Improved efficiency of the code by using this.checked instead of the original $(this).is(':checked').
Move this line:
$("#lblInformationType").text(info_lbl[type]);
into the "success" callback.
As said above, there is 2 solutions :
1) Making $.ajax asynchronous
$.ajax({
url: svc_og + "Get" + type + "InformationLabel",
async: false,
success: function(data){
info_lbl[type] = data;
}
});
2) Keep it asynchronous but doing twice :
var type = $(this).is(":checked") ? "Corporate" : "Personal";
if(!info_lbl.hasOwnProperty(type)){
$.ajax({
url: svc_og + "Get" + type + "InformationLabel",
success: function(data){
info_lbl[type] = data;
$("#lblInformationType").text(data);
}
});
}
$("#lblInformationType").text(info_lbl[type]);

Categories

Resources