I'm following a simple book and It says:
function createRequest()
{
try
{
request = new XMLHttpRequest();
}
catch (tryMS)
{
try
{
request = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (otherMS)
{
try
{
request = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (failed)
{
request = null;
}
}
}
return request;
}
function getDetails(itemName)
{
var request = createRequest();
if (request==null)
{ alert("Unable to create request");
return;
}
var url= "getDetails.php?ImageID=" + escape(itemName);
request.open("GET",url,true);
request.onreadystatechange = displayDetails;
request.send(null);
}
function displayDetails()
{
if (request.readyState == 4)
{
if (request.status == 200)
{
detailDiv = document.getElementById("description");
detailDiv.innerHTML = request.responseText;
}
}
}
And all this code above is fine and it's okay to me.. but after few pages it says:
ITS VERY IMPORTANT TO REMOVE VAR KEYWORD BEFORE request VARIABLE so the callback can reference the variable...
but how come in example above it worked? is it coincidence if we call a variable 'request' that it will map with global variable in a createRequest method?
Take a look on image below:
Why is this happening ? in one example var before request variable is used and everything is fine, in another var is avoided so the method in callback might access it.. but how come method in a callback is accessing a request variable in first example...
It's confusing because there are 2 similar examples, with different explanations..
EDIT
P.S it says request has to be a global ? :o
Thanks guys
Cheers
In both examples, implicit global variables are created so they can be shared with the callback.
When the second request variable is created, it creates a local variable inside the getDetails function. So when createRequest() returns the global variable, the local variable becomes a reference to it.
This is rather bad advice and shows a lack of understanding on the writers' part. But it seems to be an old text, since activeX objects are deprecated by now, so maybe globals used to be less frowned upon. The proper way is to either send the responseText or responseXML as a parameter to the callback or send the entire request as the parameter for the callback.
Maybe the writer didn't want to make the request code more complex, but imho, this is not a good way to teach people things.
function createRequest( method, url, callback, payload ) {
var request = new XMLHttpRequest();
if ( !request ) {
alert( "Unable to create request" );
return null;
}
request.open( method, url );
request.onreadystatechange = function() {
if (request.readyState === 4 && request.status === 200 ) {
callback( request.responseText );
}
};
request.send( payload );
};
function getDetails( itemName, callback ) {
createRequest( "GET", "getDetails.php?ImageID=" + escape(itemName), callback, null );
};
function displayDetails( detail ) {
var detailDiv = document.getElementById("description");
detailDiv.innerHTML = detail;
};
getDetails( "someItemName", displayDetails );
you are right, in your first example, function createRequest is not using var, which mean you are creating a global variable request when excute request = new XMLHttpRequest();.
We should avoid using gobal var in most situation.
function createRequest() {
try {
// add var so it's not global variable
var request = new XMLHttpRequest();
} catch (tryMS) {
try {
request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (otherMS) {
try {
request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (failed) {
request = null;
}
}
}
return request;
}
function getDetails(itemName)
{
var request = createRequest();
if (request==null)
{ alert("Unable to create request");
return;
}
var url= "getDetails.php?ImageID=" + escape(itemName);
request.open("GET",url,true);
// create anonymous function to call your callback and pass `request` as local variable
request.onreadystatechange = function(){
displayDetails(request);
};
request.send(null);
}
function displayDetails(request)
{
if (request.readyState == 4)
{
if (request.status == 200)
{
detailDiv = document.getElementById("description");
detailDiv.innerHTML = request.responseText;
}
}
}
Related
So basically I have an ajax function pretty standard one. Like so:
function ajax_call(rest_req, url, success_callback, fail_callback) {
// if (request_in_progress)
// return;
// request_in_progress = true;
var xhttp = new XMLHttpRequest;
xhttp.onreadystatechange = function () {
if (this.readyState == 4) {
// request_in_progress = false;
if (this.status == 200) {
success_callback(this);
}
else {
fail_callback(this);
}
}
};
xhttp.open(rest_req, url, true);
xhttp.send();
}
When I use the ajax function this way:
(function() {
function setup() {
ajax_call("GET", "url1", function(xhttp) {
response = JSON.parse(xhttp.responseText);
if (response["error"] != 100)
document.getElementById('url1-reading').innerHTML = '---';
else
document.getElementById('url1-reading').innerText = response["response"];
},
function() {}
);
ajax_call("GET", "url2" , function(xhttp) {
response = JSON.parse(xhttp.responseText);
if (response["error"] != 100)
document.getElementById('url2-reading').innerHTML = '---';
else
document.getElementById('url2-reading').innerText = response["response"];
},
function() {}
);
console.log('Refresh');
}
setInterval(setup, 1000);
})();
This code behaves differently than what I expect. When I run this code, there are some times when the results that were suppose to go to url1 success_callback goes inside url2's success_callback.
To put another way the response variable inside url1 ajax_call is what I expected to show up as response variable for url2. So in effect the ajax_call seem to not know what success_callback is for what even though I explicitly pass it in as a parameter.
I'm coming from a C++ background so this is a difficult concept to grasp. How do I do this the right way? I hope my question is clear. Please tell me what is not clear so I can clarify.
The way you declare it, response is a global variable. Try changing response = to let response =
i have a function with a XML-HTTP-Request. Unfortunately i don't get back my DB-result when i call this function getUserdataByToken() <-- working, via a second Function sendPost(wall).
I just want to have the return value (array) inside my second function but the value is always "undefined". Can someone help me?
function getUserdataByToken() {
var token = localStorage.getItem("token");
var userDataRequest;
//-AJAX-REQUEST
var xhttp;
if (window.XMLHttpRequest) {
xhttp = new XMLHttpRequest();
} else {
// code for IE6, IE5
xhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
var url= window.location.protocol+"//"+window.location.host+"/getuserdatabytoken";
var param = "token=" + token;
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
userDataRequest = JSON.parse(xhttp.responseText);
if (userDataRequest.success === "false") {
warningMessage('homeMessage', false, userDataRequest.message);
} else {
return userDataRequest;
}
}
};
xhttp.open("POST", url, true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send(param);
}
Function call via second Function (AJAX) leads too "undefined" Value for "userDataRequest" (return of function 1).
function sendPost(wall) {
var content;
var token = localStorage.getItem("token");
var userData = getUserdataByToken(); // PROBLEM
console.log(userData); // "leads to undefined"
alert(userData); // "leads to undefined"
… Ajax Call etc…
P.S. it's my first post here in stackoverflow, I'm always grateful for tips.
Thanks!
The userdata value only exists within the anonymous Ajax callback function, and you only return it from there. That is pointless because there is nowhere for it to be returned to; certainly the value does not get returned from getUserdataByToken. Don't forget that Ajax calls are asynchronous; when sendPost calls getUserdataByToken the request won't even have been made.
Generally you'd be much better off using a library like jQuery for this whole thing. Apart from making your code much simpler, it will allow you to use things like Promises which are explicitly intended to solve this kind of problem.
(And, do you really need to support IE5? Are you sure?)
I'm checking if a file at a certain local URL exists via a XMLHttpRequest, kind of a workaround peek at the filesystem. Using the pingFile function described below, I try to see if I get a 200 or 404 for a given file and perform some actions depending on that result.
function pingFile(theURL, callback)
{
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (this.readyState === this.DONE) {
if (callback !== null) {
return callback(this.status);
} else {
return this.status;
}
}
};
req.open("HEAD", theURL);
req.send();
}
var q = pingFile('images/image1.png', null);
However, when I check the value of q, it is always undefined. I'm missing something about the asynchronous nature of an XHR here, I think, but I haven't been able to find where to wait so that this.status has either of the values I would expect from a file check.
EDIT: I've tried adding return 4; after req.send(); and that always gives q the value 4 regardless of whether the file is there.
How do I get the status value of a XMLHttpRequest back from the function it's in?
For async operations you could use callbacks or promises. Here is a simple example with callbacks:
(function () {
function pingFile(theURL, success, error) {
var req = new XMLHttpRequest();
req.onload = function (e) {
if (this.status === 200) {
success(e);
} else {
error(e);
}
};
req.open("HEAD", theURL);
req.send();
}
function fileExist(e) {
alert('File exist!');
}
function fileNotExist(e) {
alert('File does not exist!');
}
pingFile('images/image1.png', fileExist, fileNotExist);
}());
I have created some little jt code, but it gives me error
function Mind(){
var request = "request";
var reply = "reply";
var words = '';
this.Reply = function(){
if(request == words.nouns[0].noun){
reply = words.nouns[0].noun;
}
else
reply = this.words.nouns[0].noun;
}
this.SetRequest = function(req){
request = req;
}
this.GetReply = function(){
return reply;
}
this.Parse = function(u){
var xmlhttp = new XMLHttpRequest();
var url = u;
var result;
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
words = JSON.parse(xmlhttp.responseText);
}
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
return result;
}
this.Construct = function(){
words = this.Parse('mind/words.json');
}}
var mind = new Mind();
mind.Parse('mind/words.json');
and here is my json file
{
"nouns": [
{"noun": "child"},
{"noun": "father"}
]
}
In command live all goes well, but when I run this code, appears error
Uncaught TypeError: Cannot read property 'nouns' of undefined
Mutliple errors. The most fundamental one is that your code ignores that XMLHttpRequest is async, and wont return a value in the same way as "regular" functions. Read about it here: How to make a function wait until a callback has been called using node.js. The TL;DR is that you have to pass in a "callback-function" to your parse-method and "return" your value using that function, instead of using a return-statement. Google for "javascript callbacks" and read a few tutorials if this concept is new to you!
You also have some minor errors, like returning result from Parse, but never actually setting result to anything. Also words is being assigned in multiple places in a way that doesn't really make sense. But both of these things will go away when you solve the sync/async issues.
EDIT:
Essentially the fix looks like this:
this.Parse = function(u, callback){ // this "callback" is new
var xmlhttp = new XMLHttpRequest();
var url = u;
var result;
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
words = JSON.parse(xmlhttp.responseText);
callback(null, words); // we're "returning" the words here
}
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
// no return statement here!
}
this.Construct = function(){
this.Parse('mind/words.json', function(error, words) {
// here you can use your words!
});
}}
Following is the way I know for adding parameters to request handlers for XMLHttpRequest.
var request = new XMLHttpRequest();
function ABC() {
if (request) {
request.open('GET', url, true);
request.onreadystatechange = function() { handler(param1, param2); };
request.send();
}
}
function handler(param1, param2) {
if (request.readyState == 4) {
if (request.status == 200) {
//do something on success
} else {
alert("Invocation Errors Occured");
}
}
}
That is fine and good. But, kindly look at the following code.
var request = new XMLHttpRequest();
function ABC() {
if (request) {
request.open('GET', url, true);
request.onreadystatechange = handler;
request.send();
}
}
function handler(evtXHR) {
if (request.readyState == 4) {
if (request.status == 200) {
//do something on success
} else {
alert("Invocation Errors Occured");
}
}
}
Here, i'm calling the handler without any parameter, but i'm getting an object of type XMLHttpRequestProgressEvent in the evtXHR parameter of the code.
Now I have two questions.
How am I getting evtXHR parameter when I make a parameter-less call?
How to add a parameter along with evtXHR so that I still get the XMLHttpRequestProgressEvent object?
So, I want something like this:
function handler(evtXHR, myParam) {
if (request.readyState == 4) {
if (request.status == 200) {
//do something on success
} else {
alert("Invocation Errors Occured");
}
}
}
You aren't making a call. the XHR object is. The handler function is being called by the XHR object in response to receiving the event.
Don't try to pass it as an argument. Use a closure instead.
Such:
var myData = 1234;
request.onreadystatechange = handler;
function handler(event) {
alert(myData); // Use myData from the wider scope instead of trying to pass it as an argument
}