Javascript program not executing correctly - javascript

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

Related

ajax not setting value on declared variable [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
I have a problem with this javascript function. What I'm trying to do is, finding a specific "Material Description" using ajax call. When I try to console.log the ajax function, the data is showed up. But when I'm setting to an array, it won't set the array value and skipped. Using "async: false" give me this warning:
Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user’s experience.
without async will give me undefined result.
$('#iBarcode').keypress(function (keyPressed) {
if (keyPressed.which == 13) {
var barcode = $('#iBarcode').val()
var splitted = new Array()
var arrayCnt = -1;
for (var i = 0; i < barcode.length; i++) {
var flagStart;
if (barcode.charAt(i) == ')') {
flagStart = true
i += 1
arrayCnt += 1
splitted[arrayCnt] = ''
}
if (barcode.charAt(i) == ('(')) {
flagStart = false
}
if (flagStart == true) {
splitted[arrayCnt] = splitted[arrayCnt] + barcode.charAt(i)
}
}
console.log(setMatDesc(splitted[0])) //value showed here
splitted[arrayCnt + 1] = setMatDesc(splitted[0]) //value not showed here and skipped?
splitted[arrayCnt + 1] = currentDate
$('#iBarcode').val('').focus
console.log(splitted)
}
})
function setMatDesc(MatID) {
var result
$.ajax({
url: '#Url.Action("Get_MatDesc")',
type: 'GET',
async: false,
data: { MatID: MatID },
success: function (data) {
result=data
},
error: function (xhr) {
alert('error');
}
})
return result
}
I would appreciate the help, thanks.
You need to provide a call back function which will get executed after ajax call completes like:
function setMatDesc(MatID, calback) {
var result
$.ajax({
url: '#Url.Action("Get_MatDesc")',
type: 'GET',
async: false,
data: { MatID: MatID },
success: function (data) {
callback(data); // note this
},
error: function (xhr) {
alert('error');
}
});
}
and at calling end do like:
setMatDesc(splitted[0],function(result) {
splitted = result;
splitted[arrayCnt + 1];
splitted[arrayCnt + 1] = currentDate;
});
The code might not work as i have not tested but this is the way to return the data from a function doing ajax call as the ajax call executes asynchronously and the function executes the body before the ajax call completes back from the server.

JQuery Ajax won't error

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

how do i wait for multiple ajax calls to complete from a .each loop

I am running a loop that updates records on a table but i need to wait for all of the records to update before i continue on.
How can I have jquery wait until all of the calls in the loopselectedrows function completes? I have read about .deferred and .when but i am not sure how to implement
either. they both do not seem to able to handle an array of calls if i where to change over to using an array for the ajax posts. Any help would be greatly appreciated.
this is the button that starts it all :
click: function () {
// validate all rows
var $selectedRows = $('#Table1').jtable('selectedRows');
LoopSelectedRows($selectedRows, 'Validate');
/// wait here until all ajax calls have completed
// then continue with checking
// check for any row with an error
var $ValidatedRows = $('#Table1').jtable('selectedRows');
var boolCheck = checkValidatedRows($ValidatedRows);
// if all records are succesfull then add them
// else alert user
if (boolCheck == true) {
LoopSelectedRows($selectedRows, 'Add');
}
else {
alert("Please correct invalid records and try again");
}
}
the first thing this does is take all of the records from the table and passes them to a looping function.
this is the looping function -
function LoopSelectedRows(SelectedRecords, actionType) {
if (SelectedRecords.length > 0) {
//Show selected rows
SelectedRecords.each(function () {
var record = $(this).data('record');
record.PERSON_NAME = record.PERSON_ID;
// Actions for loop
// Validation Action
if (actionType == 'Validate') {
check = validateRecord(record);
}
// call add function
if (actionType == 'Add') {
AddRecordToTable(record);
}
})
};
}
this loop can either validate or add records for now i am only worried about the validation function
this is the validation function:
function validateRecord(dataRecord) {
$.ajax({
url: "./ValidateAddRecord",
type: 'POST',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify(dataRecord),
success: function (data) {
if (data.Result == "OK") {
// update record with message
$('#table1').jtable('updateRecord', { record: data.Record });
}
else {
// display error
alert(data.Message);
}
}
});
}
One fairly clean way to know when multiple ajax calls are done is to use promises and jQuery's $.when(). That will give you a callback when all the ajax calls are done. It will take a little bit of reorganization of your code to use that.
First, you return the $.ajax() promise from validateRecord():
function validateRecord(dataRecord) {
return $.ajax({
url: "./ValidateAddRecord",
type: 'POST',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify(dataRecord),
success: function (data) {
if (data.Result == "OK") {
// update record with message
$('#table1').jtable('updateRecord', { record: data.Record });
}
else {
// display error
alert(data.Message);
}
}
});
}
Then, you collect all the promises in LoopSelectedRows() and return a master promise using `$.when():
function LoopSelectedRows(SelectedRecords, actionType) {
var promises = [];
if (SelectedRecords.length > 0) {
//Show selected rows
SelectedRecords.each(function () {
var record = $(this).data('record');
record.PERSON_NAME = record.PERSON_ID;
// Actions for loop
// Validation Action
if (actionType == 'Validate') {
promises.push(validateRecord(record));
}
// call add function
if (actionType == 'Add') {
promises.push(AddRecordToTable(record));
}
})
};
// return master promise
return $.when.apply($, promises);
}
Then, you can use that final promise to know when everything is done.
click: function () {
// validate all rows
var $selectedRows = $('#Table1').jtable('selectedRows');
LoopSelectedRows($selectedRows, 'Validate').then(function() {
// all the ajax calls in LoopSelectRows are done now
// check for any row with an error
var $ValidatedRows = $('#Table1').jtable('selectedRows');
var boolCheck = checkValidatedRows($ValidatedRows);
// if all records are succesfull then add them
// else alert user
if (boolCheck == true) {
LoopSelectedRows($selectedRows, 'Add');
} else {
alert("Please correct invalid records and try again");
}
});
FYI, you probably also want to change AddRecordToTable() to return a promise so it can work the same way (though it is not required because you aren't trying to wait for that operation to be done).
$.active returns the number of active Ajax requests. Use $.active==0 means no ajax requests are active. You could also use ajaxStart and ajaxStop to keep track of when requests are active.
Thank you jfriend00, your solution seems to have solved my issues.
Below is the updated version i am now using for anyone interested :
click: function () {
// validate all rows
var $selectedRows = $('#table1).jtable('selectedRows');
LoopSelectedRows($selectedRows, 'Validate').then(function () {
// check for any row with an error
var $ValidatedRows = $('#table1).jtable('selectedRows');
var boolCheck = checkValidatedRows($ValidatedRows);
// if all records are succesfull then add them
// else alert user
if (boolCheck == true) {
LoopSelectedRows($selectedRows, 'Add');
}
else {
alert("Please correct invalid records and try again");
}
});
}
// loop function
function LoopSelectedRows(SelectedRecords, actionType) {
var promises = [];
if (SelectedRecords.length > 0) {
//Show selected rows
SelectedRecords.each(function () {
var record = $(this).data('record');
// Actions for loop
// Validation Action
if (actionType == 'Validate') {
promises.push(validaterecord(record));
}
// call add function
if (actionType == 'Add') {
AddRecordToTable(record);
}
})
};
return $.when.apply($, promises);
}
// validate function
function validaterecord(dataRecord) {
var def = $.Deferred();
$.ajax({
url: "./ValidateAddRecord",
type: 'POST',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify(dataRecord),
success: function (data) {
if (data.Result == "OK") {
// update record with message
$('#table1).jtable('updateRecord', { record: data.Record });
// resolve token
def.resolve();
}
else {
// display error
alert(data.Message);
}
}
});
return def.promise();
}

calling jquery ajax function from javascript [duplicate]

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

What design pattern should I apply when checking multiple ajax request completion?

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

Categories