Figuring out XMLHttpRequest

Hello all,

I’m using a technique from the Simply Javascript book to grab a value from a script using AJAX (without the X). I can’t see why I’m not getting the response I want.

I’m calling a url with some numbers tacked on the end. Typing this new total url into my browser gives me a page with other data on it. I’m trying to grab that other data.

I took out the setTimeout code because it was in the way of debugging, but that will be back in there later on.

Here’s some of my code


    postcodePrice: function(input) {
        var pc = input.value;
        //bunch of code to clean pc, comes out as "pcnum", a 4-digit number

        try {
            var req = new XMLHttpRequest();
        }
        catch(err) {
            try{
                var req = new ActiveXObject("Microsoft.XMLHTTP");
            }
            catch(err) {
                var req = null;
            }
        }
      
        if(req != null) {
            req.open('GET', 'http://example.com/grafkosten.php?postcode=' + pcnum, true);

            req.onreadystatechange = function() {
                if(req.readyState == 4) {
                    alert('ONREADYSTATECHANGE LOL');
                    [b]if(req.status == 200 || req.status == 304) {[/b]
                        alert('OH HAI 200OK');
                    }
                    else {
                        alert('OH NOES AJAX DUN BROKE');
                    }
                }
            };
            req.send(null);
            alert('now what?');
        }
    },

What’s happening is I do reach state 4 complete, but when I check to see if the status is 200 (which is is, I have confirmed and also it states this in Firebug), it goes to the else statement and alerts OH NOES.

Opera doesn’t give me any of the alerts. Safari and Chrome do. Is there something else I need to know about Opera?

I don’t know why. Am I asking for the status incorrectly? And I generally don’t have an issue with Firebug but here I just get the URL (and the 200 OK status) in the console and I can see the Headers I’ve sent, but not much else.

Where do I start?

I would start with alerting the req.status in the else block. If it is not 200 according to the browser, I’d like to know what the browser thinks it is.

Also, I would factor the whole AJAX stuff out of the function and create

  1. A function that returns an XHR object – or false if it can’t be done
  2. A function for a GET request and a function for a POST request
  3. A very onreadystatechange function that accepts a callback function - in that function you manage the readyState and the status and if all is okay fire the callback function

Writing the 3 things above again and again for each function becomes a pain real fast.

So basically you call the GET or POST function with a URL and a callback, and that function creates the XHR object, ties the onreadystatechange to its own readystatechange function and then fires the request.

Meh, pounding my head on the keyboard and googling helped.

My dev area and the other dev area aren’t the same domain technically. I didn’t think it would be an issue asking for a response from another domain’s script (and I didn’t see it mentioned in my book, tho I didn’t read further as I didn’t get that far with my code anyway), but that was the main issue.

I noticed when I dug down that my status was always 0. Also I often got this annoying message in Firebug about uncaught exceptions. Googling that had all these people complaining about AdBlock Plus. Well I don’t have AdBlock anything but that led me to suspect NoScript, which, yeah, needed the actual local server address and port in the whitelist. Ok, that was solved.

The Status 0 came up with lots of people either not connection to their servers correctly, or they were trying to test locally which doesn’t work. So I figured it was how we had our dev areas set up. I copied my stuff over to where the PHP script was running (so exact same domain port alles). Viola. Status now = 200. Great. I would have loved to read it somewhere instead of finding a bunch of people asking on forums why they were getting Status 0, but, whatever. Maybe I’ll learn it better this way.

A function that returns an XHR object – or false if it can’t be done

Since I’m not dealing with anything lower/older than IE6
Do I want to get any more complicated than
if (thethingisnotnull) {
do stuff;
}
?
I have already gone to the one-liner because I’m a lazy typist:
var req = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject(“Microsoft.XMLHTTP”);
not messin with that other ActiveX thing.

  1. A function for a GET request and a function for a POST request

Prolly on a future list of mine though my colleague has this kinda love affair with GET for everything.

  1. A very onreadystatechange function that accepts a callback function - in that function you manage the readyState and the status and if all is okay fire the callback function

This I will prolly end up doing Monday, or something like it. The “A” in “AJAX” is pissing me off. The script calls the server with .open and then while that’s going on, the script continues on until it gets to where I return the answer I’m expecting… before I get it. Damn. So I’m expecting I’ll need some sort of mechanical cuckoo clock and a heap of closures to get that going right.

Writing the 3 things above again and again for each function becomes a pain real fast.

Luckily I’m still in the moron-newbie phase where I’m only writing it once for one input. This is in a function who’s called by a function who’s called by a function, but so far only for one form input and if I were told to add more, what I have now isn’t flexible enough to take those.

So basically you call the GET or POST function with a URL and a callback, and that function creates the XHR object, ties the onreadystatechange to its own readystatechange function and then fires the request.

The last part I don’t think I get yet. Two readystatechanges?

Well basically you create a readystatechange that’s a wrapper for all other readystatechanges. So, something like this:


function myOnreadystatechange(xmlHttp, handler) {
	if (xmlHttp.readyState == 4) {
		if (xmlHttp.status == 200 || xmlHttp.status=304) {
			if (xmlHttp.responseXML) {
				handler(xmlHttp.responseXML);
			} else {
				alert('Received invalid answer from the server.');
			}
		} else {
			alert('Error while loading the page (' + xmlHttp.status + ')');
		}
	}
}

Then, we you need make an AJAX call you can just something like this:


var x = XMLHttpRequest();
x.open('GET', url);
x.onreadystatechange=myOnreadystatechange(x, function(data) { 
  alert(data); // do something when the AJAX call is done
  // inside this closure readyState=4 and status is either 200 or 304
  // no need to check, because that's already handled by myOnreadystatechange
});
x.send(null);

That way you don’t have to do the checks for readyState=4 and status=200 or status=304 for each and every onreadystatechange you write.

Does that make sense?

That way you don’t have to do the checks for readyState=4 and status=200 or status=304 for each and every onreadystatechange you write.

Right now I only have one anyway BUT I like how it makes the results wait til onreadystate is done. Very cool.