This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
jQuery ajax return value
How to return the response from an AJAX call from a function?
I have javascript. It loads data from database. I want to return true or false with respect to loading data. But I could not return it. My code has given bellow:
function CheckISRC() {
var url = "/TrackEdit/CheckISRC/" + $('#isrcid').val();
var isrc = $('#isrcid').val();
var result = false;
$.get(url, {
isrc: isrc
}, function (data) {
if (data == "true") {
result = true;
}
else {
result = false;
}
});
return result;
}
It always gives false result. Anyone has faced this kind of problem? 'Thanks advance'
If it's so important to use the function synchronously you can refactor it to:
function CheckISRC() {
var url = "/TrackEdit/CheckISRC/" + $('#isrcid').val();
var isrc = $('#isrcid').val();
var result = false;
$.ajax({
async: false,
success: function (data) {
if (data == "true") {
result = true;
}
else {
result = false;
}
},
data: { isrc: isrc }
});
return result;
}
As #ManseUK async is deprecated in jQuery 1.8 so if you want synchronous approach you should use older version.
The problem is that when you return result, It doesnt have value. because the ajax didn't finish its task. you make some callback function and when the result of ajax is returned from server, do what you want to.
Some thing like this:
function CheckISRC(Callback) {
var url = "/TrackEdit/CheckISRC/" + $('#isrcid').val();
var isrc = $('#isrcid').val();
var result = false;
$.get(url, {
isrc: isrc
}, function (data) {
if (data == "true") {
Callback(true);
}
else {
Callback(false);
}
});
}
function YourCallback(result) {
//...
}
The JQuery ajax functions are asynchronous. This means that when you initialise result to false, the result is set to true or false after the "return result;" line has run.
You can make the call synchronous but this is considered worse practice. You are often better off refactoring your code to allow for the asynchronous nature of the JQuery Ajax.
For example, where you previously had:
function myFunction() {
//Code before
var result = CheckISRC();
//Code after using result
}
you could have the following:
function myFunction() {
//Code before
CheckISRC();
}
function myFunction_callback(result) {
//Code after using result
}
where you call myFunction_callback in the success option of your ajax code like so:
function CheckISRC() {
var url = "/TrackEdit/CheckISRC/" + $('#isrcid').val();
var isrc = $('#isrcid').val();
$.get(url, {
isrc: isrc
}, function (data) {
myFunction_callback(data == "true");
});
}
Related
I'm new to javascript, but I can't get my head around this problem. I have a function that upvotes a game:
function upVoteGame(name) {
$.get("/get_gameValues", function(data) {
var alreadyExist = false;
var noVotes = false;
var games;
games = data;
for (var i = 0; i < games.length; i++) {
if (name === games[i].gameName) {
alreadyExist = true;
voteOperations();
if (userLoggedIn == false) {
alert("second");
swal("Cannot post votes", "Please log in or register to vote", "error");
}
if (noVotesLeft == false && userLoggedIn == true) {
$.ajax({
url: '/editVotes/' + games[i]._id,
type: 'PUT',
data: {
likes: games[i].likes + 1,
totalVotes: data[i].totalVotes + 1
},
success: function(result) {
alert(games[i].likes + 1);
}
});
}
refreshGameValues();
break;
}
}
//This is for us Developers!
if (!alreadyExist) {
$.post("/add_game_to_dB", {
gameName: name
}, function(result) {
alert("Introduced " + name);
});
}
});
}
Now I have the function that updates the user's votes left, voteOperations():
function voteOperations() {
$.get("/users/get_current_user", function(data) {
//var votes = 5;
for (var i = 0; i < data.length; i++) {
votesRemaining = data[i].votesRemaining;
userLoggedIn = true;
alert("votes left : " + votesRemaining);
if ((votesRemaining - 1) < 0) {
swal("No votes remaining", "Please wait 24 hours to get more votes", "error");
noVotesLeft = true;
}
if (noVotesLeft == false) {
$.ajax({
url: '/users/updateUserDetails/' + data[i].user_name,
type: 'PUT',
data: {
votesRemaining: votesRemaining - 1
},
success: function(result) {}
});
}
}
});
}
My problem is a simple problem. In the upVoteGame(name) function, I want the voteOperations() to execute before the if loop below it. However, when I run the code, the if loop below executes first and alerts the user that they are not logged in. When a user logs in, userLoggedIn is set to true, but the if loop executes firsts and tells them that they are not logged in, and then executes the voteOperations() function. I don't know why this is happening. How can I fix this so that voteOperations executes before the if loop?
This is because the voteoperations function has a get request which is asynchronous. You will need a callback function where you should include if condition
You can try:
function upVoteGame(name) {
vote(afterGet);
}
afterGet() {
if condition here
}
function vote(callback) {
$.get .... {
//after getting data
callback();
}
}
You problem occurs due to the asynchronous call of your $.get in the voteOperations function.
Since it is an asynchronous call your code continuous while your $.get is waiting to retrieve data and thus your if statement seems to trigger before your voteOperations function.
In simple words your function actually is triggered before the if statement but before it completes it's result the code continues and triggers your if statement.
You could put your if statement (logic) in the success callback of your vote operation function or use $.ajax with async:false which is not considered a good practice generally but I use it sometimes.
Something like that for example (for the second case)
$.ajax({
async: false,
.....
success: function (response) {
//
}
});
Asynchronous calls can be handled with jquery function Deffered
function upVoteGame(name) {
vote().then(doUpVoteGame(), handleError());
}
function doUpVoteGame() {
...
}
function handleError(e) {
console.error("fail", e);
}
function vote() {
var d = new $.Deferred();
$.get .... {
d.resolve();
}).fail(function(e) {
d.reject(e);
});
return d;
}
function moveIt(result, finish) {
$result = $(result);
$result.find('#main-content-wrapper').appendTo('#aem-content');
$result.appendTo('#scriptDiv');
if (finish !== undefined) {
finish();
}
}
function isAuthSpace(path) {
if (path.toLowerCase().indexOf("shop/") > 0) return true;
return false;
}
function finishInjecting() {
ProcessInjection("div.dyna-prd-lnk", parseDivTag, pumpDivTag, "Shop.aspx/GetLinks");
}
function AEMLoadError(isAuth) {
var fileToLoad = "unAuth.html";
if (isAuth) {
fileToLoad = "auth.html";
}
$("#aem-content").load(fileToLoad, finishInjecting);
}
function breakAEMLoadPath(path) {
return BreakTheAEMLoadPath === true ? "2" : path;
}
function PullAEM(path, finish) {
var isAuth = isAuthSpace(path);
var ppath = breakAEMLoadPath(path);
$.ajax({
url: ppath,
success: function (result) {
moveIt(result, finish);
},
error: function () {
AEMLoadError(isAuth);
},
dataType: "html"
});
}
When I call the above function PullAEM(path, finish), no matter what value I put in path parameter, the ajax call calls the success function, if the path has garbage in it, say it's empty, the call succeeds (even though it should fail). When it should fail, the result contains the contents of the current page which is not what path is pointing to. Anyone have any idea what I'm doing wrong?
Thanks for everyone answering so fast. I'm not sure what the problem was but after I cleaned it all up to post it up here it worked great! Though, it ay have been something you both were saying.
This is working perfectly....
I have some javascript code that updates some data to a database using a http handler, but this async call is made inside an .each loop. At the end of the loop I make a call to function CancelChanges() that refreshed the page. The problem is that the page seems to refresh before the database is updated. The .each loop seems to finish after the call to CancelChanges(). How can I make sure the page is refreshed after all the async calls are completed in the .each loop?
function SaveChanges() {
if (PreSaveValidation()) {
var allChangesSucceeded = true;
var studioId = $("#param_studio_id").val();
var baseDate = $("#param_selected_month").val().substring(6, 10) + $("#param_selected_month").val().substring(0,2);
var currency = "CAD";
var vacationPct = null;
var gvAdmissible = null;
$(".editable-unsaved").each( function() {
var newSalary = $(this).text();
var disciplineId = $(this).data("disciplineid");
var seniorityId = $(this).data("seniorityid");
var handlerCommand = "";
if ($(this).data("valuetype") === "inflated") {
handlerCommand = "AddAverageSalary";
} else if ($(this).data("valuetype") === "actual") {
handlerCommand = "UpdateAverageSalary";
}
$.get("WS/AverageSalary.ashx", { command: handlerCommand, studio_id: studioId, discipline_id: disciplineId, seniority_id: seniorityId, base_date: baseDate, currency: currency, salary: newSalary, vacation_pct: vacationPct, gv_admissible: gvAdmissible }).done(function (data) {
if (data != "1") {
$(this).removeClass("editable-unsaved");
allChangesSucceeded = true;
}
else {
alert('fail');
allChangesSucceeded = false;
}
});
});
if(allChangesSucceeded) CancelChanges();
}
}
function CancelChanges() {
var href = window.location.href;
href = href.split('#')[0];
window.location.href = href;
}
You could try using Promises and jQuery $.when
Store a list of the ajax call promises:
var defereds = [];
$(".editable-unsaved").each( function() {
//...
defereds.push($.get("WS/AverageSalary.ashx" /*...*/));
}
$.when.apply($, defereds).done(function() {
CancelChanges();
});
This should, hopefully, wait for all the ajax calls to finish before calling CancelChanges()
I think you need to change your structure a little bit, using a counter and calling CancelChanges when the counter equals the number of calls.
function SaveChanges() {
if (PreSaveValidation()) {
var studioId = $("#param_studio_id").val();
var baseDate = $("#param_selected_month").val().substring(6, 10) + $("#param_selected_month").val().substring(0,2);
var currency = "CAD";
var vacationPct = null;
var gvAdmissible = null;
var editableUnsaveds = $(".editable-unsaved"); //cache the selector here, because selectors are costly
var numOfGetsReturned = 0;
editableUnsaveds.each( function() {
var newSalary = $(this).text();
var disciplineId = $(this).data("disciplineid");
var seniorityId = $(this).data("seniorityid");
var handlerCommand = "";
if ($(this).data("valuetype") === "inflated") {
handlerCommand = "AddAverageSalary";
} else if ($(this).data("valuetype") === "actual") {
handlerCommand = "UpdateAverageSalary";
}
$.get("WS/AverageSalary.ashx", { command: handlerCommand, studio_id: studioId, discipline_id: disciplineId, seniority_id: seniorityId, base_date: baseDate, currency: currency, salary: newSalary, vacation_pct: vacationPct, gv_admissible: gvAdmissible }).done(function (data) {
if (data != "1") {
$(this).removeClass("editable-unsaved");
}
else {
alert('fail');
}
if(editableUnsaveds.length === ++numOfGetsReturned){
CancelChanges(); //now it should call when the final get call finishes.
}
});
});
}
}
function CancelChanges() {
var href = window.location.href;
href = href.split('#')[0];
window.location.href = href;
}
I'd use promises. The q library is my favorite way to implement them. But since you're using JQuery, I'd recommend following a similar approach to what I outline below, but using $.when, instead of q.allSettled
I often use promises when scraping tons of websites at once -- I need to iterate through a long list of websites, make requests for content, and do something with the content when the requests return. The last thing I want to do is send requests one at a time, handling each one as it returns.
In the abstract, that looks something like this:
function scrapeFromMany() {
var promises = [];
_.forEach(urls, function(url) {
// this makes the request
var promise = scraper(url);
// this stores the promise with the others you iterate through
promises.push(promise);
});
q.allSettled(promises).then(function(res) {
// this function is executed when all of the promises (requests) have been resolved
console.log("Everything is done -- do something with the results.", res);
});
}
Fwiw, promises aren't that easy to grok if you've never used them. If that's the case, plan on spending some time getting up to speed with the concepts. They'll change (for the much much better) the way you write async javascript, and they really are the blessed path with these sorts of operations.
Asynchronously call your check function within the "done" function handler. Keep track of how many requests have completed, and only do your processing once that's equal to the total number of expected requests.
if (PreSaveValidation()) {
var allChangesSucceeded = true;
var length = $(".editable-unsaved").length;
var completedCount = 0;
// ...
$(".editable-unsaved").each( function() {
// ...
$.get("WS/AverageSalary.ashx", data).done(function (data) {
completedCount++;
if (data != "1") {
$(this).removeClass("editable-unsaved");
// don't set all changes succeeded to true here
}
else {
alert('fail');
allChangesSucceeded = false;
}
isComplete(length, completedCount, allChangesSucceeded);
});
});
}
function isComplete(totalLength, currentLength, allChangesSucceeded) {
if (currentLength == totalLength) {
// should this be !allChangesSucceeded?
if (allChangesSucceeded) CancelChanges();
}
}
This happens because you are not waiting for the requests to complete to proceed with the loop.
To achieve so you have to set the "async" flag to false.
The call to the server should be like this:
$.ajax({
url: "WS/AverageSalary.ashx",
async: false,
data:{ command: handlerCommand, studio_id: studioId, discipline_id: disciplineId, seniority_id: seniorityId, base_date: baseDate, currency: currency, salary: newSalary, vacation_pct: vacationPct, gv_admissible: gvAdmissible },
success: function (data) {
if (data != "1") {
$(this).removeClass("editable-unsaved");
allChangesSucceeded = true;
}
else {
alert('fail');
allChangesSucceeded = false;
}
}
});
I am using ajax call to check for some validation and then submitting the form normally by html. In my ajax call,
function checkId() {
var str = $("#formObj").serialize();
$.ajax({
type : "post",
data : str,
url : "checkForId.mt",
async : false,
success : function(txt) {
if (txt == "pass") {
return "true";
} else if (txt == "same") {
$("#errorMsgIdSame").removeClass("hidden");
return "false";
}
},
error : function() {
alert("Error");
}
});
}
If the control goes to "pass", execution should continue. If it goes to "same", the execution should stop.
I am calling this ajax method from some other method.
function validateForm() {
var isValid = true;
isValid = checkId();
if (!isValid) {
$("#errorMsg").removeClass("hidden");
}
return isValid;
}
this validatioForm is called on button click. Now ajax code is working but validateForm method is not taking the return of the ajax method.
Need direction on how to carry this out so that to capture the return from the ajax method and how to return from the ajax method.
If I understood your question correctly, you want to return the result of an inner function from an outer function. This definition of checkId does just that.
function checkId() {
var result;
var str = $("#formObj").serialize();
$.ajax({
type : "post",
data : str,
url : "checkForId.mt",
async : false,
success : function(txt) {
if (txt == "pass") {
result = true;
return;
} else if (txt == "same") {
$("#errorMsgIdSame").removeClass("hidden");
result = false;
return;
}
},
error : function() {
alert("Error");
}
});
return result;
}
An ajax call is asynchronous.
When you call ajax what is happening is that the ajax starts a new thread to do its task--a post in your case.
After that the code that called the ajax keeps going.
When the task that the ajax call is doing returns, it executes what ever is in its pass or fail sections depending on the task status.
So basically your checkId method completes and returns before the ajax is finished.
I would recommend triggering whatever you need the return value for from the success section or fail section like this:
success : function(txt) {
if (txt == "pass") {
newfunction(true);
} else if (txt == "same") {
$("#errorMsgIdSame").removeClass("hidden");
newfunction(false);
}
},
Edit:
function newfunction(passFail)
{
//Do something with variable passFail
}
I have 3 ajax call in one function and checkAjaxCompletion which checks each ajax completion flag.
What the code below does is send multiple separate ajax calls and interval method checks completion flags to determine whether to proceed or keep interval. (I know clearInterval is not shown but the point is I want to use something other than interval)
Current code is:
function manyAjax() {
setInterval( function() { checkAjaxCompletion(); } , 200);
ajax1();
ajax2();
ajax3();
}
function ajax1() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function ajax2() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function ajax3() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function checkAjaxCompletion() {
if(ajax1_flag == 1 && ajax2_flag == 1 && ajax3_flag == 1) {
//everything went success, do some process
}
else if(ajax1_flag == 2 || ajax2_flag == 2 || ajax3_flag == 2) {
//some ajax failed, do some process
}
else {
//all ajax have not been completed so keep interval i.e. do nothing here
}
}
But I'm hesitating to depend on using interval function because calling it so often seem such waste of memory. There must be better way to do. I'm thinking if observer pattern can be applied here but would like to hear opinions.
It is observer-notifier, if you want to call it that - but each of your ajax calls will more than likely have a callback in javascript when they complete. Why not call checkAjaxCompletion() at the end of each of them, and do nothing if you're still waiting on others?
Dustin Diaz does a great job with this example.
function Observer() {
this.fns = [];
}
Observer.prototype = {
subscribe : function(fn) {
this.fns.push(fn);
},
unsubscribe : function(fn) {
this.fns = this.fns.filter(
function(el) {
if ( el !== fn ) {
return el;
}
}
);
},
fire : function(o, thisObj) {
var scope = thisObj || window;
this.fns.forEach(
function(el) {
el.call(scope, o);
}
);
}
};
The publisher:
var o = new Observer;
o.fire('here is my data');
The subscriber:
var fn = function() {
// my callback stuff
};
o.subscribe(fn);
To unsubscribe:
var fn = function() {
// my callback stuff
};
o.subscribe(fn);
// ajax callback
this.ajaxCallback = function(){
$.ajax({
type: "POST",
url: ajax.url,
data: {key: value},
async : !isAll,// false使用同步方式执行AJAX,true使用异步方式执行ajax
dataType: "json",
success: function(data){
if(data.status == 'successful'){
selfVal.parent().find('.msg').addClass('ok').html(msg.ok);
}else if(data.status == 'failed'){
checkRet = false;
selfVal.parent().find('.msg').removeClass('ok').html(msg.error);
}else{
checkRet = false;
}
return this;
}
});
}
return this;
Maybe you want to check your inputvalue callback ajax in your form;
You can view my website Demo, hope help you.
http://6yang.net/myjavascriptlib/regForm
Okay my idea was to make your own object that can handle sending an array of requests, keep a history of each request and do what i'm gonna call 'postProccessing' on each response, here is a probably very dodgy bit of code to hopefully demonstrate what I am thinking.
var Ajax = function() {
var request, callback, lst;
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
} else if (window.ActiveXObject) {
request = new ActiveXObject("Microsoft.XMLHTTP");
}
request.onreadystatechange = handleResponse;
this.history = [{}];
this.send = function(args) {
for (var i = 0; i < args.length; i++) {
if (args.url) {
request.open(args.type || 'GET', args.url);
}
request.send(args.data || null);
callback = args.callback;
lst++;
}
}
function handleResponse() {
var response = {
url: '',
success: true,
data: 'blah'
};
history.push(response);
if (postProccess()) {
callback();
}
}
function postProcess() {
if (this.history[lst].success) {
return true;
} else {
return false;
}
}
}