javascript AJAX call causing a timing problem - javascript

Program A has a form which submits to program B. The program A form has an input :
<input type = 'hidden' name = 'token' id = 'token' value = ''>
The value is set in a javascript function tkn() which is called by program A. The call:
<input type = 'button'
value = 'continue'
onclick = 'tkn()'>
The function tkn() calls an API function which returns the token. A callback function handles success or failure of the call. If there is success the callback executes
document.getElementById('token').value = response.id;
and then submits program A
var theform = document.getElementById('token');
alert('theform is ' + theform);
theform.submit();
Note the alert, which was put in there while I was debugging, to make sure the form was properly picked up before being submitted.
As long as the alert is there, everything is fine. Program A is submitted to Program B, the token goes through to B and does whatever it is supposed to do.
However, if the alert is not there, the procedure fails, because the token is passed through to program B as a blank.
I found an explanation of the problem here, along with a solution I don't understand: function not working correctly unless there is an alert . Apparently it is a timing problem because AJAX is asynchronous. The alert gives the AJAX call time to complete.
He suggests that the solution is to provide a callback where "you will perform the necessary actions". I have a callback function, but I don't know what are the "necessary actions" it should take to ensure that the AJAX call completes. Here is the callback:
function tokenHandler( status, response ){
// (ie. if the "error" key exists in the response).
if (response.hasOwnProperty( "error" )){
alert( "Something went wrong! + response.error.message);
return;
}
else{
document.getElementById('token').value = response.id;
}
}//function tokenhandler
Can someone enlighten me about what "necessary actions" the callback function should take to make sure the AJAX call is complete?
In the comments it is suggested that putting the
document.getElementById('token').value = response.id;
in the callback is the correct thing, because we only get to the callback if the AJAX response is complete. Well, that's where the line of code it -- in the callback function. So maybe the problem isn't an AJAX timeing problem. But it sure is true that the thing won't run without that alert.
Does anyone have any other suggestions?
API call:
Stripe.createToken(
{
number: cardno,
exp_month: emth,
exp_year: eyr,
cvc: cvv,
address_zip: '19004'
},
amount,
tokenHandler,);
A SOLUTION HAS BEEN FOUND. I put the submit into the callback function instead of in the main tkn() function. That fixed the problem. So after all it is a timing problem, but I think it is between the callback function and the main function. I assumed the submit wouldn't happen until the callback was finished, but apparently that is not the case.

In the SO link you gave us, the answer says that the alert() paused the code. This makes the code work because AJAX does not run synchronously, which means the code does not wait for the AJAX call to finish. Therefore, the code and the AJAX run together and the AJAX hasn't given back the result when your code finishes running. But, alert()s stop the code from running temporarily until you click done, so the AJAX has time to finish.
Please add all of your JS code so I can see how it can be fixed. I will edit this once you do it.
You need to put your code inside the AJAX callback. Example:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// Code here
}
};
xhr.open("GET", "filename", true);
xhr.send();
Maybe you could delete your onclick and add an event listener in the // Code here. Example:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("YourInput").addEventListener("click", function() {
var theform = document.getElementById('token');
alert('theform is ' + theform);
theform.submit();
});
}
};
xhr.open("GET", "filename", true);
xhr.send();

Related

Confused about callback

I started studying JS and came across callbacks and promises. I am a little confused, read dozens of sources, but could not exactly find answer. For example a code from mozilla
var xmlhttp = new XMLHttpRequest(),
method = 'GET',
url = 'https://developer.mozilla.org/';
xmlhttp.open(method, url, true);
xmlhttp.onload = function (data) {
console.log(data)
};
xmlhttp.send();
From description of onload :
callback is the function to be executed when the request completes successfully. It receives a ProgressEvent object as its first argument. The value of this (i.e. the context) is the same XMLHttpRequest this callback is related to.
Where does it actually get ProgressEvent from? And how should I differentiate it from
var myFunc = function (data) {
console.log(data);
}
myFunc('ALERT!!!');
Should not I pass parameter to the function?
callbacks are function passed as argument to another function to be executed later.In your case you want to execute something after XMLHttpRequest finish doing its job. So you need to pass a success function to be executed after ajax finish loading it's content.
why we use callback?
after finish loading you might want to do something with the result of http request.You cant do it in the onload handler.
xmlhttp.onload = function(result){
// do stuff with result
}
But you will need to write a lot of code inside the onload event handler.So by passing callback you can keep the workspace clean.Write code for processing the result inside the callback.See the following code
function ajax(callback){
var xmlhttp = new XMLHttpRequest(),
method = 'GET',
url = 'https://developer.mozilla.org/';
xmlhttp.open(method, url, true);
xmlhttp.onload = function (data) {
callback(data) // your callback will execute after http request finish loading
};
xmlhttp.send();
}
function success(result){ // this function will be used as callback
// do stuff with result.
}
// call ajax function and pass the callback function to be executed after loading
ajax(success)
ProgressEvent :
ProgressEvent object contains the data associated with the current request state.The follwoing is your progress event object.See the red underlined properties.loaded is the number of bytes loaded.and total is the total byte to be loaded.This is actually the data size.Thus you can determine how many bytes to be loaded and how many byte actually loaded.If those two properties are similar then the load is complete.That's what onload do.After loading complete both are 191(byte).I have a file that is 191 byte in size.That means the loading is complete.
The callback arguments are provided by whatever part of the code executes the function later. In this case, such code is executed by the browser itself and, being a browser library, there's no JavaScript source code you can inspect.
Perhaps it's easier to understand with a pure JavaScript example:
function printMessageInConsole(message) {
console.log("Message is: %s", message);
}
function doSomeStuff(runThisWhenFinished) {
runThisWhenFinished("I am finished with it");
}
doSomeStuff(printMessageInConsole);

Trouble with callback function in asynchronous 'Post'

I am new to javascript, and I am having an issue with a line of code executing before the previous line has finished. From what I understand, I need to create a callback function which will make the last line wait for the previous line to finish. My program takes user input and uses an asynchronous 'post' to send it to a website, and then a message is returned. My original problem occurred when I had the two following lines of code together:
req.send(JSON.stringify(payload))
event.preventDefault();
preventDefault() is not waiting for the send() function to finish. I have tried implementing a callback function, but I am having problems with that as well.
function sendReq(callback){
req.send(JSON.stringify(payload), function(){
callback();
});
}
sendReq(function(){
event.preventDefault();
});
Any suggestions would be much appreciated. Here is my entire code in case that helps.
var apiKey = "appid=fa7d80c48643dfadde2cced1b1be6ca1";
document.addEventListener('DOMContentLoaded', bindButtons);
function bindButtons(){
document.getElementById('dataSubmit').addEventListener('click', function(event){
var req = new XMLHttpRequest();
var payload = {longUrl:null};
payload.longUrl = document.getElementById('inputData').value;
req.open('POST', 'http://httpbin.org/post&' + apiKey, true);
req.setRequestHeader('Content-Type', 'application/json');
var response = JSON.parse(req.responseText);
req.addEventListener('load',function(){
if(req.status >= 200 && req.status < 400){
document.getElementById('outputData').textContent = response.longUrl;
}
else
console.log("Error in network request");
});
function sendReq(callback){
req.send(JSON.stringify(payload), function(){
callback();
});
}
sendReq(function(){
event.preventDefault();
});
});
}
You misunderstand how callbacks work. Check out this article from recurial.com: Understanding callback functions in Javascript
You can't "wait" in JavaScript[*] - due to something called "Run-to-completion" semantics: your code always runs in response to an event (such as "DOMContentLoaded", "click", or XHR's "load") and no more events - and no other event handlers - will be processed until your currently running code finishes (typically by return-ing from the outermost function -- the event handler).
Long-running JS code makes the web page freeze, which is why you were asked to write an asynchronous request in the first place -- synchronous XHR will cause the page to freeze while your code waits for the response from the server.
To avoid the freezes and still get the job done, you can structure your code as a series of callbacks: after you start an asynchronous request you return from the current function and let the system call you back when it has the response. The only moment when you can use the response is in the callback, by the very definition of the callback.
In your case, the callback that indicates that the response is available is the load handler. That's where you should move your var response = JSON.parse(req.responseText); line.
PS. preventDefault() is completely unrelated to your situation, it can't be used to "wait for the send() function to finish"; it's used in cases when you handle an event (such as onsubmit for a <form>) and you want to prevent something that the browser does by default when this event fires (in the <form> example -- well -- submitting the form).
PPS. After you figure out the basics and start writing code that has more than 2 callbacks in a row, look up "promises".
PPPS. [*] Ignore this remark, I added it just to be precise, as it will only confuse you at this stage: You can't "wait" in JavaScript unless you're writing a "generator" and/or using the currently unavailable async/await).

How do I execute a Javascript function requires a value after an onload function is completed that gives the value?

I know its a long question, so allow me to explain as best as I can.
I have two javascript functions that I want to run after the page loads, we will call them function1() and function2().
function1() uses AJAX to retrieve information from the database that will arrange the contents in a div from the information obtained in the database. It also returns the contents from the database once the function has finished.
function2() requires the value from the database in order to run properly, so it needs to wait until function1() returns its value before function2() runs. Unfortunately my code is not working, and without going into too much detail, below is a schematic of the code:
function function1() {
if (some_cookie_exists) {
//run some code
} else {
//send parameters through "POST"
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var a = some_value_from_database;
// change div content
return a;
}
}
//sending parameters
}
function function2(a) {
//run code that depends on value of "a"
}
window.onload = function() {
var data = function1();
function2(data);
The error I get is that var data is undefined. function1() retrieves the data successfully, and runs as I intended it to, but function2() does not execute at all, because the value is missing. Can anyone figure out why I am getting this and how I should go about solving this?
NOTE: I am really only familiar with Javascript (still novice at that), I know essentially nothing about JQuery, so if you do use this to fix the code, please explain to me why this works (it will save me trouble later)
AJAX is asynchronous (that's what the first A stands for). The results of the AJAX operation are not available in function1(), they're retrieved in the onreadystatechange handler that you attach to the XMLHttpRequest object. So it's not clear how you could be doing
var a = some_value_from_database;
in function1().
What you need to do is call function2() from the onreadystatechange handler.
If you post the actual implementation of function1 we may be able to provide more specific details.
UPDATE:
Here's how to call function2() when the value becomes available from the AJAX call:
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var a = some_value_from_database;
function2(a);
}
}
Do it with a callback.
function function1(callback) {
/* ... */
callback(data); // instead of return
}
var function2 = function(data) { // important: make "function2" a variable so that it can be passed as an argument later on
/* ... */
}
window.onload = function() {
function1(function2); // important: no parentheses after function2, otherwise it would be executed right away
}
Because ajax by definition is asynchronous, function2 will start executing before the ajax completes in function1. JQuery would be useful here, as you can place function2 in the success callback of the ajax call in function1.
So include JQuery in your HTML and the following JS should work:
$(function() { //same as onload
function1() ;
}
function function1() {
$.ajax({
url: "url here",
type: "GET",
success: function(data) { // data is what is returned in ajax response
// rearrange divs
function2(data);
}
});
);
function function2(data) {
}
More on the JQuery ajax function here:
http://api.jquery.com/jQuery.ajax/

AJAX does not synchronously

I've got an issue similar to this question here:
Javascript and AJAX, only works when using alert()
I have an AJAX call to update a field in the database when finalizing a form. However, the call doesn't seem to be reaching the controller. When I put an alert in, it works. I've currently got it set to synchronous because of the issue, but even then, without the alert, it only reaches the controller about 1 in every 5 or six times. This is the AJAX bit:
function finalize() {
if (!confirm("Are you sure?"))
return;
$("#finalizebutton").attr('disabled', 'disabled');
var request = new XMLHttpRequest();
var url = "/Operation/Finalize/";
request.open("GET", url, false);
request.send();
$("#otherformstuff").attr('disabled', 'disabled'); //a few disable calls
}
On the control side I have approximately:
public ActionResult Finalize()
{
db.setfinalized(true); //breakpoint here that only gets hit about 1 in 5 tests
return Content("Finalized");
}
Even when there is an alert shoved in there it sometimes doesn't work.
Oddly enough, I put an alert for request.responseText and it gave me the response from the control without the control ever actually processing it...
Any thoughts on this are appreciated.
Because you tell it to be synchronous.
Your problem is with this line:
request.open("GET", url, false);
The open method takes 3 arguments. Method, url, and the third is a boolean that tells it whether or not the request should be asynchronous.
Just change the false to true, and the request will be async.
request.open("GET", url, true);
But you could also just replace that entire block of XHR code with this one line..
$.get('/Operation/Finalize/');

how to return variable from the function called by onreadystatechange=function() [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 years ago.
I'm using the ajax technique in combination with php and I want to know how to get the return variable from the function that is called by onreadstatechange.
A java function is called onsubmit to then call a php script to verify some things in my database and return true or false depending on the results.
Here is where I run into problems, I want the onsubmit="return snappyajaxfunction()" to return false or true based on the results from the php.
My question is, how do I get the result of false or true from the stateChanged function to become the return for snappyajaxfunction.
I tried doing this for kicks: result = request.onreadystatechange=StateChanged with no luck.
I've also tried saving the responsetxt to a global variable then returning the global variable in snappyajaxfunction with no luck.
snappyajaxfunction()
{
request.onreadystatechange=stateChanged;
request.open("GET",url,true);
request.send(null);
return result;
}
function stateChanged()
{
if (request.readyState==4)
{
return request.responseText;
}
}
The purpose of this is to script is to verify the username / password entered by the user with the username / password stored in my database. If it they don't match it returns false and the form will not submit, if it does the form submits and the user is brought to the welcome page...
You could do:
function stateChanged()
{
if (request.readyState==4)
{
OnStateChanged(request.responseText);
}
}
Where OnStateChanged is a function that act as an event handler...
EDIT: in OnStateChanged you can then submit or not your form based on response
EDIT2: On the server when you check the u/p, if they're right log the user right on and return the status to JavaScript.. then in the JavaScript instead of resubmitting a form, just reload/redirect the page if it is successful or display an alert otherwise...
It is just not possible to return something from a function by an asynchronous operation in it... the original thread of execution is long gone. The asynchronous operation is executed by another thread (If I remember correctly, don't flame).
Thanks
jQuery won't automagically fix the fact that he's trying to base his submission on the results of an asynchronous request.
What you can do is the following:
1) Set the form onsubmit to simply call snappyajaxfunction();
2) In stateChanged, if the readystate is 4, obtain a reference to the form and do the following:
form.onsubmit = function() { return true; };
form.submit();
Basically - Set the onsubmit to always return true and then force it to submit again. For added usability you may want to disable the button causing the submission while waiting for statechanged to happen. And then re-enable it.
feel free to check out this tutorial on ajax.
It will show you how to properly use ajax step-by-step
as inkedmn has suggested, I would recommend using jquery or any of the other js frameworks
The problem is that ajax calls are asynchronous. That means the response is separate from the request. You have to modify your code to handle that. You cannot (should not) make http calls synchronous.
Look at this code. It works, and you'll be able to read the response:
var req = new XMLHttpRequest();
req.open('GET', url, true);
req.onreadystatechange = function (ev) {
if (req.readyState == 4) {
alert(req.responseText);
}
};
req.send(null);
To make your code work you can use closures and pass functions as parameters.2 properties javascript is very good at.
snappyajaxfunction(url, fn)
{
var request...
request.onreadystatechange=function()
{
if (request.readyState==4)
{
fn(request.responseText);
}
};
request.open("GET",url,true);
request.send(null);
}
to use it you can build a function like
var doSomething = function(response){
alert(response);
};
snappyajaxfunction('/country/code/32', doSomething);
The closure allows 'request' to be available within the function that handles the onreadystatechange.
The function 'fn' is passed as a parameter of snappyajaxfunction.

Categories

Resources