jQuery $.post() request doesn't work unless ran twice - javascript

Here are two functions.
function getUserInformation(UserID) {
$.post("assets/scripts/chat/get_user_info.php", {
UserID: UserID
}, function (data) {
if (data == "error") {
alertBar('negative', 'There was an error sending the message');
}
window.username = data;
})
}
function CreateChatBox(UserID) {
if ($('#' + UserID).length == 0) {
getUserInformation(UserID);
alert(username);
}
My issue is, that when the CreateChatBox() function is executed, it has to be clicked twice in order for it to actually work. How ever if I remove the getUserInformation() function from the CreateChatBox() function the CreateChatBox() function executes successfully.
Could anybody help me with this issue? Thanks.
---Edit (extra Detail)----
When I click a link <a onclick = "CreateChatBox()">Some link</a> nothing happens. But when I click it the second time it does work. If I remove the function getUserInformation() from the CreateChatBox() function the CreateChatBox() function works first time when the link is clicked.

It is because the you are not waiting for ajax response to complete. When you click first time the ajax call is made through post and by second click the response is most likely available so you get it. You can see this putting alert inside the success handler.
function getUserInformation(UserID) {
$.post("assets/scripts/chat/get_user_info.php",
{
UserID: UserID
},
function(data){
if (data == "error") {
alertBar('negative','There was an error sending the message');
}
window.username = data;
alert(window.username);
});
}
function CreateChatBox(UserID) {
if ($('#'+UserID).length==0) {
getUserInformation(UserID);
}
//alert(username);
}

This is AJAX which means request is asynchronous. What you should do is to pass callback function as the second argument of your getUserInformation which will be invoked when data is available:
function getUserInformation(UserID, callback) {
$.post("assets/scripts/chat/get_user_info.php", {UserID: UserID}, function(data) {
if (data == "error") {
alertBar('negative', 'There was an error sending the message');
}
callback(data);
})
}
function CreateChatBox(UserID) {
if ($('#'+UserID).length == 0) {
getUserInformation(UserID, function(username) {
alert(username);
});
}
}

Related

execution out of order inside ajax callback function javascript

I have a following ajax operation that is intended to (1) show spinner gif before sending ajax request, and after after the request is complete, (2) hide the gif and 3 display appropriate alert messages.
Finally (4) reload the page.
Here's the code:
$.ajax({
url: rUrl,
data: {
id: rID,
requisitionStatus: rStatus,
comment: rComment
},
type: "POST",
cache: false,
beforeSend: function() {
$("#requisitionStatusDialog").dialog('close');
$('#ajax_loader_my').show();
},
success: function(data, resp) {
var json = data;
var obj = JSON && JSON.parse(json) || $.parseJSON(json);
if (obj.status == "success") {
alert('Success! ' + obj.message);
location.reload();
} else if (obj.status == "error") {
alert('Error!' + obj.message);
}
},
error: function(data, resp) {
$("#updateDialog").dialog('close');
console.log(resp);
},
complete: function() {
$('#ajax_loader_my').hide();
}
});
But in this case, alert pops up first while the spinner gif still shows up, and reloads the page after clicking OK.
I even tried hiding the gif in success callback itself instead of using complete:
success: function(data, resp) {
var json = data;
var obj = JSON && JSON.parse(json) || $.parseJSON(json);
if (obj.status == "success") {
$('#ajax_loader_my').hide();
alert('Success! ' + obj.message);
location.reload();
} else if (obj.status == "error") {
alert('Error!' + obj.message);
}
},
Both gives the same result.
The reason your alert pops up before the spinner is hidden is the success code runs before complete which hides the spinner. The reason it reloads is because after the alert you send location.reload();
Check that $('#ajax_loader_my').hide(); is actually hiding the spinner. The element that is or contains the spinner in your html must be have its id set to ajax_loader_my.
If you open Chrome or Firefox Dev tools you should be able to send $('#ajax_loader_my').hide() and see what happens.
Rewrite the code this way, this will put your alert and location related code in event queue which will run when it will be free.
if(obj.status=="success") {
$('#ajax_loader_my').hide();
setTimeout(function(){
alert('Success! '+obj.message);
location.reload();
},0);
}
Hi you should try to use promises here is the documentation Jquery promises, I made this on the fly it can have some errors but is just an example:
$( function() {
function AjaxCall(rID,rStatus,rComment){
return $.ajax({
url: 'request.php',
data: {
id: rID,
requisitionStatus: rStatus,
comment: rComment
},
type: "POST",
cache: false,
beforeSend: function() {
$("#requisitionStatusDialog").dialog('close');
$('#ajax_loader_my').show();
}
})
}
$( "#requisitionStatusDialog" ).dialog();
$("#yourbuttonInputId").on('click',function(event) {
AjaxCall().done(function(data,response){
var obj = JSON.parse(data);
if (obj.status == "success") {
alert('whe are on done!');
}
}).fail(function(data,response){
$("#updateDialog").dialog(' close');
}).always(function(data){
if(confirm('You have finished the request. Click OK if you wish to continue ,click Cancel to reload the page.'))
{
$('#ajax_loader_my').hide();
$("#requisitionStatusDialog").dialog('open');
}else{
location.reload();
}
});
});
} );
EDIT: Check this jsfiddle it will guide you to elaborate your code
Hope it Helps
I would rather suggest to use an empty div or span with an Id.
Than display success in the html of that div.
For Example:
$('#ajax_loader_my').hide();
setTimeout(function () {
$('#successDiv').html('Success! ' + obj.message);
location.reload();
}, 2000);

.preventDefault() is not working in conditionals

I have a bit of a problem. When a form is submitted, I wan't to check some things about it, and if something is wrong, I want to prevent it from submitting and then show an error on the client side. Everything seems to work fine except the form keeps submitting. It even shows the error on client side for a split second before it submits.
$('#register').on('submit', function (e) {
e.preventDefault();
var username = $("#register-username"),
name = $("#register-name"),
email = $("#register-email"),
password = $("#register-password"),
confirmPassword = $("#register-confirmPassword");
checkUsername(function (res) {
if (res) {
checkEmail(function (res) {
if (res) {
this.submit();
} else {
clearErrors();
email.toggleClass('input-error');
}
});
} else {
clearErrors();
username.toggleClass('input-error');
}
});
});
function checkEmail(callback) {
$.get("/checkEmail/" + $('#register-email').val(), function (data) {
if ( data == undefined ) {
callback(true);
} else {
callback(false);
}
});
}
function checkUsername (callback) {
$.get("/checkUsername/" + $('#register-username').val(), function (data) {
if ( data == undefined ) {
callback(true);
} else {
callback(false);
}
});
}
function clearErrors () {
var arr = [
$("#register-username"),
$("#register-name"),
$("#register-email"),
$("#register-password"),
$("#register-confirmPassword")
];
arr.forEach(function(el) {
el.removeClass('input-error');
});
}
Update:
Now I am just confusing myself. checkUsername() returns undefined from my server, I know for a fact, but somehow it is reaching the 'else' statement where checkUsername() is called. I've added the rest of my code. Should clear some confusion.
The call to preventDefault is made from the anonymous callback function you're passing to checkUsername. If the anonymous function is called asynchronously, then it's too late to cancel the event.
Assuming the problem is due to asynchronous code not shown, an effective way is to use preventDefault for the jQuery submit handler and use native submit when all validation passes
Something like:
$('#register').on('submit', function (e) {
e.preventDefault();// prevent jQuery submit
// after all validation passes
this.submit();// submit native method won't trigger jQuery handler again
})
You need to return false from validation to stop the current submitting event, and then manually send the post request on success from when the callbacks have successfully returned.
Since the callback is running after the validation has returned from the server then you can actually affect whether a request is made. Where as the other solutions involve trying to change how the original submit event occurs which is no longer in scope since you've already sent requests to the server at this point.
$('#register').on('submit', function (e) {
var username = $("#register-username"),
name = $("#register-name"),
email = $("#register-email"),
password = $("#register-password"),
confirmPassword = $("#register-confirmPassword");
checkUsername(function (res) {
if (res) {
checkEmail(function (res) {
if (res) {
$.post('{insert form action here}', $(this).serialize());
} else {
clearErrors();
email.toggleClass('input-error');
}
});
} else {
clearErrors();
username.toggleClass('input-error');
}
});
return false;
});
You'll have to replace the {insert form action here}, and $(this).action might work in it's place, but I'm not sure.
So I built off of charlietfl's solution and assigned the native form to a variable, and then submitted it within an anon function.
$('#register').on('submit', function (e) {
e.preventDefault()
var username = $("#register-username"),
name = $("#register-name"),
email = $("#register-email"),
password = $("#register-password"),
confirmPassword = $("#register-confirmPassword"),
form = document.getElementById('register');
$.get("/checkUsername/" + username.val(), function (data) {
if (data) {
clearErrors();
username.toggleClass('input-error');
} else {
$.get("/checkEmail/" + email.val(), function (data) {
if ( data ) {
clearErrors();
email.toggleClass('input-error');
} else {
form.submit();
}
});
}
});
});
This works.

Get configs from background page to content script in chrome extension

I'm trying to get some user configs from the background page of my chrome extension to the content script (or popup) but I'm having some problems, I think the problem is that chrome.storage.sync.get is async, I tried using callbacks but I also read that callbacks can't return the value so I have no idea how to solve this.
Here's kinda how the code looks:
popup.js:
(function() {
chrome.runtime.sendMessage({
message: "loadconfig"
}, function(response) {
console.log(response);
if (response.status === 'success') {
console.log(response);
} else {
console.log(response.except);
}
});
})();
background.js
(function() {
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
switch (request.message) {
case "loadconfig":
sendResponse(loadStuff());
break;
default:
sendResponse({
reply: null
});
break;
}
});
function loadStuff() {
var to_return_configs = {
blocked_characters: '',
good_post: ''
};
var function_status = 'failed';
var exception = '';
var blocked_characters_parsed, good_post_parsed;
try {
var to_get = ["blocked_characters_saved", "good_post_saved"];
chrome.storage.sync.get(to_get, function(result) {
to_get.forEach(function(got) {
if (got === "good_post_saved") {
to_return_configs.good_post = result[got];
}
if (got === "blocked_characters_saved") {
to_return_configs.blocked_characters = result[got];
}
});
});
exception = '';
function_status = 'success';
} catch (err) {
exception = String(err);
function_status = 'failed';
}
var to_return = {
status: function_status,
configs: to_return_configs,
except: (exception)
};
return to_return;
}
})();
The problem here is that when I'm looking at the popup.js console, "blocked_characters" and "good_post" are both empty.
How can I solve this?
You do not need Message API for communication between Popup and Background. Popup in chrome extension can directly call methods of Background .
You can do something like this
BG = chrome.extension.getBackgroundPage();
And then you can call BG.loadStuff() in your popup js.
From within loadStuff, you can pass a callback which can return data to you. So it should look like
BG.loadStuff(function(items) {
console.log(items);
});
background.js
function loadStuff(cb) {
chrome.storage.sync.get(null, function(superObj) {
cb.call(null, superObj);
});
}
For more understanding, read these
http://blog.papersapp.com/chrome-development-parent-and-child-windows/
https://stackoverflow.com/a/17276475/816213
https://stackoverflow.com/a/17378016/816213
sendResponse(function) becomes invalid when the event listener returns, unless you return true from the event listener to indicate you wish to send a response asynchronously (this will keep the message channel open to the other end until sendResponse is called). See the reference: onMessage.
Because sendResponse is called asynchronously in chrome.storage.sync.get's callback, you need to return true from the onMessage listener to prevent the function from being invalidated. Code similar is Like:
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message === 'loadconfig') {
sendResponse(loadStuff());
return true;
}
return false;
});

issue with an asynchronous while in WinJS

I have an app which invokes a WebService (callPathsToMultiTiffWS) which have two possibilities:
complete = true
complete = false
in the case complete = false I want to show a dialog which notifies to user than webService failed and two buttons:
retry action (reinvoke WS)
Exit
this is my code so far:
callPathsToMultiTiffWS(UID_KEY[9], stringCapturePaths, UID_KEY[1], UID_KEY[2], UID_KEY[3], UID_KEY[4], UID_KEY[5], UID_KEY[6]).then(
function (complete) {
if (complete == true) {//if true, it stores the id of the picture to delete
Windows.UI.Popups.MessageDialog("WS executed successfully", "Info").showAsync().then(function (complete) {window.close();});
} else {
var messageDialogPopup = new Windows.UI.Popups.MessageDialog("An error occur while calling WS, retry??", "Info");
messageDialogPopup.commands.append(new Windows.UI.Popups.UICommand('Retry', function () { /*code for recall element*/ }));
messageDialogPopup.commands.append(new Windows.UI.Popups.UICommand('Exit', function () { /*code for exit*/ }));
messageDialogPopup.showAsync();
_divInput.innerHTML = "";
}
},
function (error) { console.log("function error"); });
This works good so far, but I want the recall feature working
so I thought to embedd my code inside a loop like this
var ban = true;
while (true) {
callPathsToMultiTiffWS(UID_KEY[9], stringCapturePaths, UID_KEY[1], UID_KEY[2], UID_KEY[3], UID_KEY[4], UID_KEY[5], UID_KEY[6]).then(
function (complete) {
if (complete == true) {//if true, it stores the id of the picture to delete
Windows.UI.Popups.MessageDialog("WS executed successfully", "Info").showAsync().then(function (complete) { window.close(); });
} else {
var messageDialogPopup = new Windows.UI.Popups.MessageDialog("An error occur while calling WS, retry??", "Info");
messageDialogPopup.commands.append(new Windows.UI.Popups.UICommand('Retry', function () { ban == true; }));
messageDialogPopup.commands.append(new Windows.UI.Popups.UICommand('Exit', function () { ban == false; }));
messageDialogPopup.showAsync().then(function (complete) {
console.log("no ps no");
});
}
},
function (error) { console.log("function error"); });
if (ban == false) break;
}
this loop executes the webService, but it doesn't wait for user interaction to trigger the webservice by touching one of the buttons, it is an endless loop with calls to my webService, how to fix this??
thanks in advance for the support
If I'm not missing something, it looks like the error is caused because your code isn't designed to run the next set of tasks after the asynchronous call to showAsync returns. Because the call to showAsync is non-blocking, the while loop will start over again and make another call to the Web service. And because THAT call (callPathsToMultiTiffWS) is also non-blocking, the loop will start over again, triggering another call to callPathsToMultiTiffWS. And over again, and again.
My recommendation is to break out the next call to the Web service so that it will only be triggered when the user makes a selection. If you separate your concerns (move the calls to the Web service into different function or module than the UI that informs the user of an issue), then you can probably fix this.
Kraig BrockSchmidt has a great blog post about the finer details of Promises:
http://blogs.msdn.com/b/windowsappdev/archive/2013/06/11/all-about-promises-for-windows-store-apps-written-in-javascript.aspx
-edit-
Here's some code that I wrote to try to demonstrate how you might accomplish what you're trying:
function tryWebServiceCall(/* args */) {
var url = "some Web service URL";
return new WinJS.xhr({ url: url }).then(
function (complete) {
if (complete) {
return new Windows.UI.Popups.MessageDialog("WS executed successfully", "Info").showAsync().then(
function () { /*do something */ });
} else {
var messageDialogPopup = new Windows.UI.Popups.MessageDialog("An error occur while calling WS, retry??", "Info");
messageDialogPopup.commands.append(new Windows.UI.Popups.UICommand('Retry', function () {
return tryWebServiceCall( /* args */);
}));
messageDialogPopup.commands.append(new Windows.UI.Popups.UICommand('Exit', function () { return; }));
return messageDialogPopup.showAsync();
}
});
}

weird problem - change event fires only under debug in IE

I have form autocomplete code that executes when value changes in one textbox. It looks like this:
$('#myTextBoxId)').change(function () {
var caller = $(this);
var ajaxurl = '#Url.Action("Autocomplete", "Ajax")';
var postData = { myvalue: $(caller).val() }
executeAfterCurrentAjax(function () {
//alert("executing after ajax");
if ($(caller).valid()) {
//alert("field is valid");
$.ajax({ type: 'POST',
url: ajaxurl,
data: postData,
success: function (data) {
//some code that handles ajax call result to update form
}
});
}
});
});
As this form field (myTextBoxId) has remote validator, I have made this function:
function executeAfterCurrentAjax(callback) {
if (ajaxCounter > 0) {
setTimeout(function () { executeAfterCurrentAjax(callback); }, 100);
}
else {
callback();
}
}
This function enables me to execute this autocomplete call after remote validation has ended, resulting in autocomplete only when textbox has valid value. ajaxCounter variable is global, and its value is set in global ajax events:
$(document).ajaxStart(function () {
ajaxCounter++;
});
$(document).ajaxComplete(function () {
ajaxCounter--;
if (ajaxCounter <= 0) {
ajaxCounter = 0;
}
});
My problem is in IE (9), and it occurs only when I normally use my form. Problem is that function body inside executeAfterCurrentAjax(function () {...}); sometimes does not execute for some reason. If I uncomment any of two alerts, everything works every time, but if not, ajax call is most of the time not made (I checked this by debugging on server). If I open developer tools and try to capture network or debug javascript everything works as it should.
It seems that problem occurs when field loses focus in the same moment when remote validation request is complete. What I think it happens then is callback function in executeAfterCurrentAjaxCall is executed immediately, and in that moment jquery validation response is not finished yet, so $(caller).valid() returns false. I still do not know how alert("field is valid") helps in that scenario, and that could be sign that I'm wrong and something else is happening. However, changing executeAfterCurrentAjaxCall so it looks like this seems to solve my problem:
function executeAfterCurrentAjax(callback) {
if (ajaxCounter > 0) {
setTimeout(function () { executeAfterCurrentAjax(callback); }, 100);
}
else {
setTimeout(callback, 10);
}
}

Categories

Resources