var ajax = function(url,callback) {
if(window.XMLHttpRequest) {
xml = new XMLHttpRequest();
}
if(window.ActiveXObject) {
var xml = new ActiveXObject("Microsoft.XMLHTTP");
}
this.xml = xml;
alert(xml);
xml.onreadystatechange = function(callback) {
callback = callback();
if(xml.readyState == 4 && xml.status == 200) {
alert(xml);
}
}
xml.open('GET',url,true);
xml.send(null);
}
ajax('/server/eChck.php?email=email#yahoo.com',function(){
alert(xml);
});
the callback() wont work. Produces syntax error. can any explain to me how I would code this so I could put my callback() inside of the parameter?
Thanks,
Jon W
There are two mistakes here:
xml.onreadystatechange = function(callback) {
callback = callback();
if(xml.readyState == 4 && xml.status == 200) {
alert(xml);
}
}
First, you're creating the ready state change handler as a function that takes a parameter, which isn't incorrect but you've named that parameter "callback". That means that inside the state change handler, "callback" refers to that parameter, not to the "callback" passed in to the outer function.
Second, by assigning to "callback" the result of calling the callback function, you'll overwrite the value each time the event handler is called.
I think you want something like this:
xml.onreadystatechange = function() {
if(xml.readyState == 4 && xml.status == 200) {
callback();
}
}
edit — In addition to those changes, you should declare the "xml" variable in your "ajax" function:
var ajax = function(url,callback) {
var xml;
And take out this line:
this.xml = xml; // take this out
Related
Im learning JS and working with passing variables between functions. I am trying to execute a function on click whilst passing a variable between functions. I can pass the variable by executing the function on page load, but cant do it on a click function.
function getData() {
let xmlhttp = new XMLHttpRequest();
let url = "https://jsonplaceholder.typicode.com/posts";
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
myArr = JSON.parse(this.responseText);
//myFunction(myArr);
document.getElementById("start2").addEventListener("click", myFunction(myArr));
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send();
}
getData();
function myFunction(arr) {
// var arr = getData();
var out = "";
var i;
for (i = 0; i < arr.length; i++) {
out += '<p>' + arr[i].id + '</p><br>';
}
document.getElementById("answer-holder").innerHTML = out;
}
It does not work, since addEventListener expects a function as its second argument. But you do not provide a function. Instead you provide the result of evaluating myFunction, which is undefined (since myFunction does not return anything).
// when `addEventListener` is called, `myFunction` is also called immediately,
// instead of first being called when the event is triggered
document.getElementById("start2").addEventListener("click", myFunction(myArr));
You can fix the code by instead providing a function, that calls myFunction with your chosen argument.
document.getElementById("start2").addEventListener("click", function() {
myFunction(myArr);
});
The problem is you are calling the function when trying to set the onClick listener:
document.getElementById("start2").addEventListener("click", myFunction(myArr));
As suggested by Thomas, you have to pass a function to addEventListener. However, I would suggest the newer lambda notation:
document.getElementById("start2").addEventListener("click", () => myFunction(myArr));
I have 3 functions in my javascript code. I want to call the 3rd function as soon as both function1 and function2 are over executing.
func_one();
func_two();
func_three(); // To be called as soon both of the above functions finish executing.
Note that they may take variable time since function 1 and 2 are for fetching geolocation and some ajax request respectively.
How about this?
func_one() {
// Do something
func_two();
}
func_two() {
// Do something
func_three();
}
func_three() {
// Do something
}
There are two ways to solve this problem.The first one is to create callback functions as parameters for your existing functions.
function one(param_1 .. param_n, callback) {
var response = ... // some logic
if (typeof callback === "function") {
callback(response);
}
}
The second way is to use Promises like:
var p1 = new Promise(
function(resolve, reject) {
var response = ... //some logic
resolve(response);
}
}
var p2 = new Promise( ... );
p1.then(function(response1) {
p2.then(function(response2) {
//do some logic
})
})
You can try like this
var oneFinish = false;
var twoFinish = false;
function one(){
//...
oneFinish = true; // this value may depends on some logic
}
function two(){
//...
twoFinish = true; // this value may depends on some logic
}
function three(){
setInterval(function(){
if(oneFinish && twoFinish){
//...
}
}, 3000);
}
Since your functions func_one and func_two are making service calls you can call the functions on after other at the success callback of the previous function. Like
func_one().success(function(){
func_two().success(function(){
func_three();
});
});
i am new to JavaScript, i am learning javascript from a book "Visual Quickstart guide",
i am struggling with the following code logic, as function definition shows it expects an argument,
function getNewFile(evt) {
makeRequest(this.href);
evt.preventDefault();
}
but when the function is being called there is not argument being passed to it,
function initAll() {
document.getElementById("makeTextRequest").addEventListener("click",getNewFile,false);
document.getElementById("makeXMLRequest").addEventListener("click",getNewFile,false);
}
i do not understand the default behavour of this function when no arguments have been passed to it,
complete code from the book
window.addEventListener("load",initAll,false);
var xhr = false;
function initAll() {
document.getElementById("makeTextRequest").addEventListener("click",getNewFile,false);
document.getElementById("makeXMLRequest").addEventListener("click",getNewFile,false);
}
function getNewFile(evt) {
makeRequest(this.href);
evt.preventDefault();
}
function makeRequest(url) {
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
else {
if (window.ActiveXObject) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {
}
}
}
if (xhr) {
xhr.addEventListener("readystatechange",showContents,false);
xhr.open("GET", url, true);
xhr.send(null);
}
else {
document.getElementById("updateArea").innerHTML = "Sorry, but I couldn't create an XMLHttpRequest";
}
}
function showContents() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
if (xhr.responseXML && xhr.responseXML.childNodes.length > 0) {
var outMsg = getText(xhr.responseXML.getElementsByTagName("choices")[0]);
}
else {
var outMsg = xhr.responseText;
}
}
else {
var outMsg = "There was a problem with the request " + xhr.status;
}
document.getElementById("updateArea").innerHTML = outMsg;
}
function getText(inVal) {
if (inVal.textContent) {
return inVal.textContent;
}
return inVal.text;
}
}
The below code, the 'getNewFile' method is being passed in as a parameter and isn't actually executed until the 'click' even is raised, then it is executed with the expected parameter arguments.
function initAll() {
document.getElementById("makeTextRequest").addEventListener("click",getNewFile,false);
document.getElementById("makeXMLRequest").addEventListener("click",getNewFile,false);
}
In Javascipt, Functions are objects just as numbers, strings, array, etc. If the function name doesn't have "()" double parenthesis after it (with or without out arguments) then it's not being executed right then, but rather being passed as a parameter for future reference/execution.
Here's a couple simple examples of passing Functions as a parameter:
Example 1
function example1() {
alert('hello');
}
function executor1(f) {
// execute the function passed in through argument 'f'
f();
}
executor(example1);
// example1 isn't executed/called until it's called from within executor1
Example 2
function add(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}
function alertMath(a, b, f) {
var result = f(a, b);
alert(result);
}
// alerts the message of "3"
alertMath(1, 2, add);
// alerts the message of "6"
alertMath(2, 3, multiply);
// alerts the message of "3"
// this shows a function being defined inline
alertMath(6, 2, function(a, b) {
return a / b;
});
I hope this gives you a little more context surrounding this as to what's going on.
In here :
function getNewFile(evt) {
makeRequest(this.href);
evt.preventDefault();
}
getNewFile is the function reference, getNewFile(parameter) is the function call.
As you can see here :
document.getElementById("makeTextRequest").addEventListener("click",getNewFile,false);
getNewFile (function reference, not function call) is passed on to addEventListener. According to the addEventListener documentation, the second parameter is the listener, which is the function that will be called when the event triggers.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 9 years ago.
I have a function which declares a variable with the var keyword. It then launches an AJAX request to set the value of the variable, and this variable is then returned from the function.
However, my implementation fails and I 'don't know why.
Here's a simplified version of the code;
function sendRequest(someargums) {
/* some code */
var the_variable;
/* some code */
request.onreadystatechange =
//here's that other function
function() {
if (request.readyState == 4) {
switch (request.status) {
case 200:
//here the variable should be changed
the_variable = request.responseXML;
/* a lot of code */
//somewhere here the function closes
}
return the_variable;
}
var data = sendRequest(someargums); //and trying to read the data I get the undefined value
AJAX requests are asynchronous. Your sendRuest function is being exectued, the AJAX request is being made but it happens asynchronously; so the remainder of sendRuest is executed, before the AJAX request (and your onreadystatechange handler) is executed, so the_variable is undefined when it is returned.
Effectively, your code works as follows:
function sendRuest(someargums) {
/* some code */
var the_variable;
/* some code */
return the_variable;
}
var data = sendRequest(someargums);
And then some time later, your AJAX request is completing; but it's already too late
You need to use something called a callback:
Where you previously may have had
function () {
var theResult = sendRuest(args);
// do something;
}
You should do:
function () {
sendRuest(args, function (theResult) {
// do something
});
};
and modify sendRuest as follows:
function sendRuest(someargums, callback) {
/* some code */
//here's that other function
request.onreadystatechange =
function() {
if (request.readyState == 4) {
switch (request.status) {
case 200:
callback(request.responseXML);
/* a lot of code */
//somewhere here the function closes
}
}
This is not about scope - its about async processing.
The function sendRuest ends before the onreadystatechange function gets called.
You can't return the variable from the function that creates the ajax callback since the variable won't be set yet.
The ajax function in turn has to call another callback with the returning result.
request.onreadystatechange =
function() {
if (request.readyState == 4) {
switch (request.status) {
case 200:
//here the variable should be changed
the_variable = request.responseXML;
the_callback(the_variable);
Instead a plain string variable, you can use an object.
function sendRuest(someargums) {
var the_variable = {
data: null,
setData: function(data){ this.data = data;}
}
//here's that other function
request.onreadystatechange =
function() {
if (request.readyState == 4) {
switch (request.status) {
case 200:
//here the variable should be changed
the_variable.setData(request.responseXML);
}
return the_variable;
}
Anyway, your last line isn't going to work. When the function 'sendRuest' ends, the XHR request is not completed. You need to use timers to check the value of 'the_variable.data' (very bad) or use callbacks as stated in other answers.
Sergio.
In a situation like the code below how would you go about accessing a variable value that is in an anonymous function? I would like to return the bool value of filterData(xmlhttp.responseText, thisForm); which will be boolean to the main checkAvailable function. Thanks in advance.
function checkAvailable(thisForm) {
var xmlhttp = httpRequest();
var isValid = true;
var un = document.getElementById('u_username').value;
var email = document.getElementById('u_email').value;
xmlhttp.onreadystatechange = function(isValid) {
if (xmlhttp.readyState == 4) {
//I WANT TO ACCESS THIS isValid VARIABLE FROM MAIN FUNCTION checkAvailable
isValid = filterData(xmlhttp.responseText, thisForm);
}
}
xmlhttp.open("GET","profile_fetch_reg_info.php?do=available&un="+un+"&email="+email+"",true);
xmlhttp.send(null);
return isValid;
}
The way i have it now
function validateRegForm(thisForm) {
var isValid = true;
var warningIcon = "";//for later in case we want to use an icon next to warning msg
checkAvailable(thisForm, function(isValid) { });
if(isValid == false)
window.scroll(0,0);
alert(isValid);
return false;//isValidForm;
}
function checkAvailable(thisForm, resultFunction) {
var xmlhttp = httpRequest();
var un = document.getElementById('u_username').value;
var email = document.getElementById('u_email').value;
xmlhttp.onreadystatechange = function(isValid) {
if(xmlhttp.readyState == 4) {
isValid = filterData(xmlhttp.responseText, thisForm);
resultFunction(isValid);
}
}
xmlhttp.open("GET","profile_fetch_reg_info.php?do=available&un="+un+"&email="+email+"",true);
xmlhttp.send(null);
}
Modify the checkAvailable function to take an additional parameter which is the function to call with the result.
function checkAvailable(thisForm, resultFunction) {
..
xmlhttp.onreadystatechange = function(isValid) {
if (xmlhttp.readyState == 4) {
//I WANT TO ACCESS THIS isValid VARIABLE FROM MAIN FUNCTION checkAvailable
isValid = filterData(xmlhttp.responseText, thisForm);
resultFunction(isValid);
}
}
}
Then, you can call it something like this:
checkAvailable(thisForm, function(isValid) {
// Use the isValid value which is the result of the checkAvailable call.
});
EDIT
Here is a change to the modified code you posted.
function validateRegForm(thisForm) {
var isValid = true;
var warningIcon = "";//for later in case we want to use an icon next to warning msg
checkAvailable(thisForm, function(isValid) {
if(isValid == false)
window.scroll(0,0);
alert(isValid);
}
// WARNING!! This will happen before the result is discovered.
// You'll need to modify the function that called into validateRegForm.
// It should not wait for a return parameter either.
return false;//isValidForm;
}
You need to make your XmlHttpRequest synchronous, you can do this by setting the last parameter of .open() to false, i.e.
xmlhttp.open("GET","profile_fetch_reg_info.php?do=available&un="+un+"&email="+email+"",false);
However this will lock your UI/SJS for the duration of the call
In general terms, the way to return a value from an anonymous function would be to make use of the lexical scoping nature of Javascript. To do this, you would need to declare a variable in the same scope as the anonymous function and have the function set the variable during its execution.
For example:
function a() {
var x = 1;
(function() { x = 2; })();
alert(x); // x will be 2
}
However, this is all predicated on the fact that the execution is linear, meaning that the the alert happens after the anonymous function is executed. In the code you presented above, this wouldn't happen because the XMLHttpRequest is asynchronous meaning that the onreadystatechange callback will be called at some other point in time. You could change your XMLHttpRequest to be synchronous but this would lock up the UI of your page while the request is on progress.
function checkAvailable(thisForm) {
var xmlhttp = httpRequest();
var isValid = true;
var un = document.getElementById('u_username').value;
var email = document.getElementById('u_email').value;
xmlhttp.open("GET","profile_fetch_reg_info.php?do=available&un="+un+"&email="+email+"",false);
xmlhttp.send(null);
isValid = filterData(xmlhttp.responseText, thisForm);
return isValid;
}
The best way to work with this sort of situation is to move to a completely asynchronous model. In this model, your checkAvailble() function would be restructured so that it takes a callback that is invoked after the validity is determined. Below is an example of what this might look like:
function whenAvailable(theForm, callback) {
var xmlhttp = httpRequest();
var un = document.getElementById('u_username').value;
var email = document.getElementById('u_email').value;
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState === 4) {
if (callback) {
var isValid = filterData(xmlhttp.responseText, thisForm);
callback.call(null, isValid);
}
}
}
xmlhttp.open("GET","profile_fetch_reg_info.php?do=available&un="+un+"&email="+email+"",true);
xmlhttp.send(null);
}
A call to this function would look like the following:
whenAvailable(document.getElementById('someForm'), function(valid) {
if (valid) {
// do something when valid
} else {
// do soemthing when invalid
}
});
If you need to wait for the response to proceed, use SJAX (synchronous javascript and xml) to get the result. Your script will not continue until you have received your response. Beware that timeout errors are not handled well in ie.
On the otherhand, you can use AJAX and do what you need to do inside the readyState check, instead of trying to return the value for something else to handle it.
You need to pass false as the third parameter to xmlhttp.open(). That will cause the request to be executed synchronously and your program execution will pause until it completes.
If you do this, you won’t need the anonymous function. You can just get xmlhttp.responseText directly:
function checkAvailable(thisForm) {
var xmlhttp = httpRequest();
var isValid = true;
var un = document.getElementById('u_username').value;
var email = document.getElementById('u_email').value;
xmlhttp.open("GET", your_parameters, false);
xmlhttp.send(null);
isValid = filterData(xmlhttp.responseText, thisForm);
return isValid;
}
The main drawback to this is that the browser will basically freeze until the xmlhttp.send() call completes.
If you can refactor your code so that the synchronous call is not needed, that would be better IMO.
Create an object outside the function...
obj = new Object;
obj.isValid = false;
obj.complete = false;
Then your code... except
obj.isValid = filterData(xmlhttp.responseText, thisForm);
objt.complete = true;
Make sure object definition is above the function, so that it appears global.
Now on the otherside you can detect if state 4 was achieved, and if it has then you can grab the object value.
You might also need to pass the object through in your function decalarion, it should pass it by ref and update.
The way you're accessing it within the scoped function is fine, the problem is what you're trying to do doesn't work the way you're expecting it to. As others have mentioned, you could go with a synchronous request, however that's probably not what you really want (since it'll hang your UI).
Looking at your code, I assume you have a function that needs to know whether or not your request was successful, and then continue processing. So, instead of using a flag, you need to have a callback that can execute one completion of the ajax request. Something like the following:
function checkAvailable(thisForm, callback) {
var xmlhttp = httpRequest();
var isValid = true;
var un = document.getElementById('u_username').value;
var email = document.getElementById('u_email').value;
xmlhttp.onreadystatechange = function(isValid) {
if (xmlhttp.readyState == 4) {
//I WANT TO ACCESS THIS isValid VARIABLE FROM MAIN FUNCTION checkAvailable
isValid = filterData(xmlhttp.responseText, thisForm);
}
callback(isValid);
}
xmlhttp.open("GET","profile_fetch_reg_info.php?do=available&un="+un+"&email="+email+"",true);
xmlhttp.send(null);
}
Cheat: make the ajax request handler update data in a hidden element. Then, your polling (I presume) query function can look at the hidden element to see if the "ready" flag was finally set.