PDA

View Full Version : Ajax



tech_support
04-02-2007, 09:49 AM
Ajax

This tutorial will help you learn about ajax, which basically retrieves data from another page without refreshing the current page.

If you want to learn about the history of ajax, what it stands for, then look here (http://en.wikipedia.org/wiki/AJAX). This will just help you actually create an ajax request.

There will be a code sample at the end, but if you want to learn more than I suggest you follow the step-by-step instructions.

We'll start with creating a function.

function makeRequest(url, id) {
And define http_request...

var http_request = false;
And then create a request function for Mozilla, Safari etc.


if (window.XMLHttpRequest) { // Mozilla, Safari, ...
http_request = new XMLHttpRequest();
if (http_request.overrideMimeType) {
http_request.overrideMimeType('text/xml');
}

And then create an ActiveXObject for Internet Explorer


} else if (window.ActiveXObject) { // IE
try {
http_request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
http_request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}

And check if the request is created or give an alert and terminate the script


if (!http_request) {
alert('Error creating XMLHttpRequest()');
return false;
}

Then checking if the information is recieved from the server yet or else give a "Loading..." message


http_request.onreadystatechange = function() {
var e = document.getElementById(id)
if (http_request.readyState == 4 && http_request.status == 200) {
e.innerHTML = http_request.responseText
}
else e.innerHTML = "Loading..."
};

Then requesting the URL to the server


http_request.open('GET', url, true);
http_request.send(null);

GET - For URLs that don't need to send POST data
POST - For URLs that do need to send POST data
You need to send data using http_request.send(mydata) with POST, and leave it as null when sending data with GET
Finally then closing the function


}


And here's the final script.



<script type="text/javascript">
function makeRequest(url, id) {
var http_request = false;
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
http_request = new XMLHttpRequest();
if (http_request.overrideMimeType) {
http_request.overrideMimeType('text/xml');
// See note below about this line
}
} else if (window.ActiveXObject) { // IE
try {
http_request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
http_request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}

if (!http_request) {
alert('Error creating XMLHttpRequest()');
return false;
}

http_request.onreadystatechange = function() {
var e = document.getElementById(id)
if (http_request.readyState == 4 && http_request.status == 200) {
e.innerHTML = http_request.responseText
}
else e.innerHTML = "Loading..."
};
http_request.open('GET', url, true);
http_request.send(null);
}
</script>

There are many uses for Ajax, eg. Google Docs, This "Quick Reply" thing at the bottom etc.

Have fun using ajax!

Note - There might be errors in this document, please PM me if you want to report an error, not a question.

codeexploiter
04-18-2007, 11:02 AM
First of all it is a good effort from your side (it always very difficult to write tutorials/articles/books in my opinion), thanks a lot for the ajax introduction.

There are some points I want to point out about the tutorial.

1. If a novice developer tries to get a overview of Ajax this will not provide that perfectly (unfortunate)

2. It is because you've omiited any reference to the server-side processing at all. A novice might be thinking what really happens in the server-side when it invokes the page via ajax function call. You could've extended your example a bit so that it gives an idea about the page's server-side processing from which it gets the data.


It's so easy that even pcbrainbuster can do it
You could've avoided this too.

These are my personal opinions.

regards

tech_support
04-18-2007, 11:10 AM
1. If a novice developer tries to get a overview of Ajax this will not provide that perfectly (unfortunate)
2. It is because you've omiited any reference to the server-side processing at all. A novice might be thinking what really happens in the server-side when it invokes the page via ajax function call. You could've extended your example a bit so that it gives an idea about the page's server-side processing from which it gets the data.

Hmm... How would I explain that?


it's so easy that even pcbrainbuster can do itYou could've avoided this too.

Ha. Consider it edited.

codeexploiter
04-18-2007, 11:15 AM
Hmm... How would I explain that?

Use some server-side script PHP will do the trick. Just make a simple example that gives you the server time in a form field using ajax.

jscheuer1
06-17-2007, 06:16 AM
I don't think you should worry about explaining everything. This is just a bootstrap bit of code to do the deed. I added my thanks above as, it saved me some time trying to come up with it on my own.

I do have a question about:


http_request.overrideMimeType('text/xml');
// See note below about this line

I looked over it a few times and saw no explanation and am curious. I get the general idea, but does this force text/xml, or override it? I'm guessing it overrides it.

Also, I added a little code to my 'clip' of this routine:


function makeRequest(url, id) {
var http_request = false;
if (window.XMLHttpRequest&&(!window.ActiveXObject||/http/.test(window.location.href))) { // Mozilla, Safari, IE 7 live...
http_request = new XMLHttpRequest();
if (http_request.overrideMimeType) {
http_request.over . . .

This allows IE 7 to follow the window.ActiveXObject path locally while using the more efficient window.XMLHttpRequest live. I did this because IE 7 will try to follow the window.XMLHttpRequest path locally, but cannot, due to security restrictions. At least that's a problem in IE 7 with the DD scripts that use a similar type of request test scheme, and I saw no reason why it wouldn't be here, although I might be mistaken.

And:


if (http_request.readyState == 4 && (http_request.status == 200||!/http/.test(window.location.href))) {

I'm not sure if this was necessary, but thought it might be for local testing, doesn't hurt as far as I can tell.

mwinter
06-17-2007, 11:10 PM
We'll start with creating a function.

I can't say that I really like the way you create the object. The comments are superfluous and inaccurate, too: IE also uses the first code branch.

I would start by separating the creation part from the rest of the code:



function getRequestObject() {
var object = null;

if ((typeof XMLHttpRequest == 'object') || (typeof XMLHttpRequest == 'function'))
object = new XMLHttpRequest();
else if ((typeof createRequest == 'object') || (typeof createRequest == 'function'))
object = createRequest();
else if (typeof ActiveXObject == 'function') {
/*@cc_on @*/
/*@if(@_jscript_version >= 5)
try {
object = new ActiveXObject('Msxml2.XMLHTTP');
} catch(e) {
try {
object = new ActiveXObject('Microsoft.XMLHTTP');
} catch(e) {
object = null;
}
}
@end @*/
}
return object;
}

This adds support for ICEBrowser, only exposes exception handling to versions of IE that support it, and drops the overrideMimeType call which shouldn't be necessary, anyway.



And check if the request is created or give an alert and terminate the script

Hopefully production code would do something more sensible than that.



Then checking if the information is recieved from the server yet or else give a "Loading..." message


http_request.onreadystatechange = function() {
var e = document.getElementById(id)
if (http_request.readyState == 4 && http_request.status == 200) {
e.innerHTML = http_request.responseText
}
else e.innerHTML = "Loading..."
};


What if the transaction is completed, yet the server doesn't respond with a 200 (OK) status code?

By the way, it's rather odd that you included a call earlier to the overrideMimeType method to force parsing as XML, yet then demonstrate the use of a textual response.



You need to send data using http_request.send(mydata) with POST, and leave it as null when sending data with GET

And when sending POST data, one should also send a Content-Type request header stating what form that data takes.



I do have a question about:



http_request.overrideMimeType('text/xml');
// See note below about this line


I looked over it a few times and saw no explanation and am curious.

See the XMLHttpRequest (http://www.xulplanet.com/references/objref/XMLHttpRequest.html#method_overrideMimeType) reference at XulPlanet.com.

Unless it's not possible to get the server to send the correct Content-Type header, the method shouldn't be used.

jscheuer1
06-18-2007, 04:58 AM
Notwithstanding this issue about mime-type overrides (I will research that later, but it seems to me that writing code for public release, it might be prudent to include rather than exclude it), I have 'sexed up' my code using yours (mwinter's) as a guide. This is for use in a lightbox 'clone' I've been working on (working title 'mybox') that will not rely on external libraries and should be much leaner code wise, while supporting use of on-page content that degrades well for non-javascript enabled browsers, as well as, optionally, Ajax fetched content and an iframe method that will be Flash friendly (presented here as its part in the mybox object):


makeRequest:function(url) {
mybox.box.style.backgroundColor='';
mybox.close.className='close';
mybox.close.style.width='';
var http_request = false;
if (window.XMLHttpRequest&&(!window.ActiveXObject||/http/.test(window.location.href))) { // Mozilla, Safari, IE 7 live . . .
http_request = new XMLHttpRequest();
if (http_request.overrideMimeType) {
http_request.overrideMimeType('text/xml');
}
else if ((typeof createRequest == 'object') || (typeof createRequest == 'function'))
http_request = createRequest();
} else if (window.ActiveXObject) { // IE (v7 locally)
/*@cc_on @*/
/*@if(@_jscript_version >= 5)
try {
http_request = new ActiveXObject('Msxml2.XMLHTTP');
} catch(e) {
try {
http_request = new ActiveXObject('Microsoft.XMLHTTP');
} catch(e) {
http_request = null;
}
}
@end @*/
}
if (!http_request) {
alert('Error creating XMLHttpRequest()');
return false;
}
http_request.onreadystatechange = function() {
if (http_request.readyState == 4 && (http_request.status == 200||!/http/.test(window.location.href))) {
mybox.kid1.innerHTML = http_request.responseText;
}
else
mybox.kid1.innerHTML = "Loading...";
mybox.olay.style.height=Math.max(mybox.iecompattest().offsetHeight, mybox.iecompattest().scrollHeight)+'px';
mybox.olay.style.width=Math.max(mybox.iecompattest().offsetWidth, mybox.iecompattest().scrollWidth)-(mybox.ie6wa? mybox.ie6wa() : 0)+'px';
mybox.boxLoc(mybox.box);
};
http_request.open('GET', url, true);
http_request.send(null);
},

mwinter
06-18-2007, 05:48 PM
Notwithstanding this issue about mime-type overrides (I will research that later, but it seems to me that writing code for public release, it might be prudent to include rather than exclude it), ...

I would prefer to explain the situation properly and let the author investigate what happens in their case. After all, overriding the media type isn't really a fix, but rather a stop-gap measure that may not help in all cases: when the method isn't supported.

No special software is necessary for checking this type of server behaviour: AJAX itself will do.



var httpRequest = getRequestObject();

if (httpRequest) {
httpRequest.open('GET', uri, false);
httpRequest.send(null);
alert(httpRequest.getResponseHeader('Content-Type'));
}

If no Content-Type header is sent, the getResponseHeader method will return null, otherwise the value as a string.





http_request.onreadystatechange = function() {
/* ... */
};
http_request.open('GET', url, true);


The open method should be called before setting event listeners. See the reference I posted previously.

The overall pattern for using AJAX objects should be:


Create object instance.
Call open method.
Further configure the request: add listeners, request headers, etc.
Call send method.

jscheuer1
06-19-2007, 05:12 AM
OK, I'm trying to get this about as right as I can while still keeping the code down. From what you (mwinter) write, it appears (and testing seemed to bear this out), I would need to create a separate request object and send it just in order to see if the mime type is as expected and that it would then be too late to change the mime type for that request. I would be glad to be wrong about this. However, since we don't really need to worry about overrideMimeType() being available because we are testing for its existence before we invoke it, I see no problem with just going ahead and using it. I did take to heart what you said about it making no sense to override to text/xml if text/html is what is wanted though. I had been getting some errors in FF that could only be eliminated by using self closing tags on the requested page. By changing the override to text/html, these errors went away.

Also, I had missed the first time through how you were saying that having an alert and returning false in the case where the request object couldn't be constructed didn't make too much sense in actual use. Since my code is in response to a "return get this.href" sort of onclick event, I have now chosen to return true if the request cannot be constructed. This will result in the link firing normally, loading the page if it is there and giving the server's error page for the event if the page is unavailable. If all goes well, I now return false, so that, since we now have the page as content on the 'top' page, the link will not fire.

Finally, I tried to adhere to the order in which you recommended things be carried out/invoked. Here's the new set up:


makeRequest:function(url) {
mybox.box.style.backgroundColor='';
mybox.close.className='close';
mybox.close.style.width='';
var http_request = null;
if (window.XMLHttpRequest&&(!window.ActiveXObject||/http/.test(window.location.href))) { // Mozilla, Safari, IE 7 live . . .
http_request = new XMLHttpRequest();
}
else if ((typeof createRequest == 'object') || (typeof createRequest == 'function'))
http_request = createRequest();
else if (window.ActiveXObject) { // IE (v7 locally)
/*@cc_on @*/
/*@if(@_jscript_version >= 5)
try {
http_request = new ActiveXObject('Msxml2.XMLHTTP');
} catch(e) {
try {
http_request = new ActiveXObject('Microsoft.XMLHTTP');
} catch(e) {
http_request = null;
}
}
@end @*/
}
if (!http_request)
return true;
http_request.open('GET', url, true);
if (http_request.overrideMimeType)
http_request.overrideMimeType('text/html');
http_request.onreadystatechange = function() {
if (http_request.readyState == 4 && (http_request.status == 200||!/http/.test(window.location.href)))
mybox.kid1.innerHTML = http_request.responseText;
else
mybox.kid1.innerHTML = "Loading...";
mybox.olay.style.height=Math.max(mybox.iecompattest().offsetHeight, mybox.iecompattest().scrollHeight)+'px';
mybox.olay.style.width=Math.max(mybox.iecompattest().offsetWidth, mybox.iecompattest().scrollWidth)-(mybox.ie6wa? mybox.ie6wa() : 0)+'px';
mybox.boxLoc(mybox.box);
};
http_request.send(null);
return false;
},

I'm still not clear on what the alternatives for testing only for a 200 response would be and what their implications for branching might afford, especially at that juncture in the code. However, it seems to me that if the page is missing at that point, having:

Loading . . .

just sit there until dismissed by the user (they can do that in my script), might not be so bad.

jscheuer1
06-19-2007, 04:32 PM
Ah, the light suddenly went on! We don't need to create a separate request to test if the mime type is as expected and to change it if possible, we can do:


http_request.onreadystatechange = function() {
mybox.kid1.innerHTML = "Loading...";
if (http_request.readyState == 4 && (http_request.status == 200||!/http/.test(window.location.href)))
mybox.kid1.innerHTML = http_request.responseText;
else if (http_request.overrideMimeType && http_request.readyState == 2 && http_request.getResponseHeader && http_request.getResponseHeader('Content-Type')!='text/html')
http_request.overrideMimeType('text/html');
mybox.olay.style.height=Math.max(mybox.iecompattest().offsetHeight, mybox.iecompattest().scrollHeight)+'px';
mybox.olay.style.width=Math.max(mybox.iecompattest().offsetWidth, mybox.iecompattest().scrollWidth)-(mybox.ie6wa? mybox.ie6wa() : 0)+'px';
mybox.boxLoc(mybox.box);
};

tech_support
06-22-2007, 10:19 AM
Y'know, if you want really good ajax, (and some good DOM as well) you could use the Prototype Framework (http://www.prototypejs.org/).

jscheuer1
06-22-2007, 07:17 PM
Y'know, if you want really good ajax, (and some good DOM as well) you could use the Prototype Framework (http://www.prototypejs.org/).

Don't you mean, if you want bloated code and a slew of unprotected global variables with short names, use Prototype Framework?

I already stated that I was not using external libraries, and Prototype Framework will not help beginners understand the basics anyway.

tech_support
06-23-2007, 07:03 AM
Is The Prototype Framework really that bad?
Some companies do use it...

jscheuer1
06-24-2007, 02:03 AM
For a DD type script, yes I think so. It's OK, and in some cases even beneficial, if it is used as part of a coordinated site design and all scripts on the site either use it, don't conflict with it, or act in their own scripting space.

Ideally, for a lib like that to be really worth the bother, all pages on a site that use scripts would have it linked as an external script from a single location on the server to their heads and rely upon it both extensively and wherever and whenever possible.

The reasons for this are the overhead, load time, and bandwidth involved in the lib, its complexity, and vulnerability to conflicts. If it is used in this way, as the primary script that powers all other scripts on a site, this minimizes its drawbacks and maximizes its advantages.

But, for the casual script user, it is overkill at best.

Also, from what I can gather, mootools is a superior lib. This (the choice of libs, if you are using one) is not as critical though, as is making sure to use it as efficiently and thoroughly as possible.

mwinter
06-28-2007, 06:02 AM
From what you (mwinter) write, it appears (and testing seemed to bear this out), I would need to create a separate request object and send it just in order to see if the mime type is as expected and that it would then be too late to change the mime type for that request.

This wasn't what I was trying to get at: I was describing the test as something to do during development to determine server behaviour. Based on the results, the developer can either attempt to reconfigure the server or try to fiddle the response with the overrideMimeType method (which I wouldn't recommend).

At production time, the developer should know exactly what the server will do, so no testing is required.

I would also point out that changing the media type of the response is only necessary to have the client properly process an XML response, enabling the responseXML property.

jscheuer1
05-17-2008, 09:49 PM
Revisiting this thread after much time because I've learned a few things. Here is a good somewhat advanced routine, that can handle more than one request at a time. It's fairly well commented:


function loadXmlHttp(url, id) {
var f = this;
f.xmlHttp = null;
/*@cc_on @*/ // used here and below, limits try/catch to those IE browsers that both benefit from and support it
/*@if(@_jscript_version >= 5) // prevents errors in old browsers that barf on try/catch & problems in IE if Active X disabled
try {f.ie = window.ActiveXObject}catch(e){f.ie = false;}
@end @*/
if (window.XMLHttpRequest&&!f.ie||/^http/.test(window.location.href))
f.xmlHttp = new XMLHttpRequest(); // Firefox, Opera 8.0+, Safari, others, IE 7+ when live - this is the standard method
else if (/(object)|(function)/.test(typeof createRequest))
f.xmlHttp = createRequest(); // ICEBrowser, perhaps others
else {
f.xmlHttp = null;
// Internet Explorer 5 to 6, includes IE 7+ when local //
/*@cc_on @*/
/*@if(@_jscript_version >= 5)
try{f.xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");}
catch (e){try{f.xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");}catch(e){f.xmlHttp=null;}}
@end @*/
}
if(f.xmlHttp != null){
f.el = document.getElementById(id);
f.xmlHttp.open("GET",url,true);
f.xmlHttp.onreadystatechange = function(){f.stateChanged();};
f.xmlHttp.send(null);
}
else alert('Your browser does not support AJAX!'); // substitute your desired request object unsupported code here
}


loadXmlHttp.prototype.stateChanged=function () {
if (this.xmlHttp.readyState == 4 && (this.xmlHttp.status == 200 || !/^http/.test(window.location.href)))
this.el.innerHTML = this.xmlHttp.responseText;
}

Usage:


new loadXmlHttp('requested_url', 'target_element_id')

Twey
03-18-2009, 07:41 AM
Commented it may be, but the formatting, I'm afraid, is severely lacking. :rolleyes: I think I gave myself a headache trying to read it.


try {f.ie = window.ActiveXObject}catch(e){f.ie = false;}
The statement in the try block is missing a semicolon.


catch (e){try{f.xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");}catch(e){f.xmlHttp=null;}}
This line looks like it lost a fight with Packer (http://dean.edwards.name/packer/) — although, strangely, it's one of only a few places where the space-after-control-flow-keyword convention has been observed. Well... once.


// Internet Explorer 5 to 6, includes IE 7+ when local //
Why is only this comment on a separate line?


if (this.xmlHttp.readyState == 4 && (this.xmlHttp.status == 200 || !/^http/.test(window.location.href)))
this.el.innerHTML = this.xmlHttp.responseText;
I have to ask: why is this line the only one you've indented in the entire script?

The code itself could do with some work, too. Things like:


var f = this;
Why? And why 'f'?


if (/(object)|(function)/.test(typeof createRequest))
Regular expressions are very expensive. They should be avoided for all but the most complex tasks. Certainly something this simple should not use them. There's also no need to capture — another performance hit.


/*@cc_on @*/
CC has already been turned on earlier in the code — it doesn't magically turn itself off again. Proper formatting* would make it clear that the 'end' applies to the 'if', not to the 'cc_on'.


loadXmlHttp.prototype.stateChanged=function () {
if (this.xmlHttp.readyState == 4 && (this.xmlHttp.status == 200 || !/^http/.test(window.location.href)))
this.el.innerHTML = this.xmlHttp.responseText;
}
innerHTML is, of course, entirely non-standard, and should be avoided wherever possible. It certainly shouldn't be used without a fallback. HTML is not a good format for data transfer anyway — it's semantic rather than structural, and the chances are that if one is transferring code like this, a lot of semantic or presentational code is being transferred that could more easily be stored in a template on the client-side. The required format for proper client-side rendering is rarely the optimal format for data passing and handling. You're also missing a semicolon after this statement. By making this function so specific, you're making code rese much harder. If I only want to get an XHR for some other purpose, I can see no way to do it but to copy-and-paste big chunks of the code.

Additionally, why do we check every time a new instance is created? Surely Firefox isn't going to morph into ICEBrowser while we're not looking? I'll admit that I wouldn't put it past IE, but I hardly think we can cater to that possibility.

*
// used here and below, limits try/catch to those IE browsers that both benefit from and support it
/*@cc_on @*/

// prevents errors in old browsers that barf on try/catch & problems in IE if Active X disabled
/*@if (@_jscript_version >= 5)
try {
f.ie = window.ActiveXObject;
} catch (e) {
f.ie = false;
}
@end @*/

jscheuer1
03-18-2009, 03:17 PM
Mostly all good points, Twey. And I suppose I asked for this by referring back to older work of mine (which I still feel is very useful and more complete insofar as it actually goes than most comparable routines of its type in various script libraries).

I especially like what you said about browsers not changing what method that they may use to secure the script's xmlHttp object, not even IE will do this as far as I can imagine, so it would be a performance improvement to only determine this once.

Two of your comments though I would like to explain why I think they're not or may not be correct -

About:



/*@cc_on @*/ // used here and below, limits try/catch to those IE browsers that both benefit from and support it
/*@if(@_jscript_version >= 5) // prevents errors in old browsers that barf on try/catch & problems in IE if Active X disabled


I used that syntax on mwinter's recommendation. It was his view at that time that not all IE browsers that respect @cc will automatically turn it on without the /*@cc_on @*/ coming first. At least that's how I understood his explanation as regards that.

The other thing is innerHTML. Here I have two primary thoughts:


For a basic point and shoot AJAX for content into an existing element, it's still very efficient and workable in most cases, and I'm not certain how it could be improved upon without a lot of added code, though the thought just occurred to me that there may be a way to clone the nodes - However, I seem to remember that requiring further testing and branching depending upon browser and being quite a bit more complex than one might first imagine.

Since this is just the outline of a routine, what you do with the xmlHttp.responseText or other objects/properties of the xmlHttp object is really up to you or whoever uses the code. In other words, just because I used innerHTML in the exemplar is no reason why it must be used.


In fact, I have already modified this routine numerous times for specific applications, some of these modifications make an entirely different use of the result.

Twey
03-18-2009, 04:21 PM
I used that syntax on mwinter's recommendation. It was his view at that time that not all IE browsers that respect @cc will automatically turn it on without the /*@cc_on @*/ coming first. At least that's how I understood his explanation as regards that.
That's true — the browser requires this directive to know to process conditional compilation instructions. However, it's a directive completely separate from the @if you're using. Once it's on, it's on, and it doesn't change for the rest of the script. You can put it just once at the beginning of your script, and you'll be fine.


I'm not certain how it could be improved upon without a lot of added codeDon't be afraid of extra code. Javascript comes with notoriously few primitives, but it's a powerful enough language that just about all generic code can be created and stored safely in standalone libraries. As every high-level developer knows, if it's in a library, then it doesn't really exist :p Some tasks do intrinsically depend on other, separate tasks — for example, it's trivial, given a working parser for each desired image format, to write a procedure to find the colour of a specific pixel, but it would be horribly ugly and really quite difficult to build a semi-complete parser for each format into that procedure, and even worse to build in full, generic versions that nobody else can use.


Since this is just the outline of a routine, what you do with the xmlHttp.responseText or other objects/properties of the xmlHttp object is really up to you or whoever uses the code.
That's all very well for advanced users, and I myself may well use this code or something based on it in place of the minimalist XHR-creating code currently in my libraries, since it seems to support a good deal more old browsers than I usually bother with. Newbies, though, are likely to copy-and-paste verbatim, possibly without even understanding the code. If they do take note of what it's actually doing, then they'll probably look to it as a paradigm of good code, since it's written by an expert like yourself.

jscheuer1
03-19-2009, 02:34 AM
So, as far as replacing innerHTML in the exemplar, (keeping beginners in mind) what would you recommend?

Nile
03-19-2009, 02:41 AM
This line looks like it lost a fight with Packer (http://dean.edwards.name/packer/) although, strangely, it's one of only a few places where the space-after-control-flow-keyword convention has been observed. Well... once.


Not with JSBeautifier (http://jsbeautifier.org/).

jscheuer1
03-20-2009, 10:50 AM
OK, Twey. Incorporating most of your suggestions, here is the new version. I hope that what I've done with ICEBrowser will work as written - it should if ICEBrowser acts like others in regards to functions. You still haven't gotten back to me on what you envision as a good basic replacement for innerHTML:


function loadXmlHttp(url, id) {
var f = this;
if(loadXmlHttp.xmlHttp !== null){
f.xmlHttp = loadXmlHttp.xmlHttp();
f.el = document.getElementById(id);
f.xmlHttp.open("GET", url, true);
f.xmlHttp.onreadystatechange = function(){f.stateChanged();};
f.xmlHttp.send(null);
}
else alert('Your browser does not support AJAX!'); // substitute your desired request object unsupported code here
}

loadXmlHttp.xmlHttp = null; loadXmlHttp.re = /^http/.test(window.location.href);
/*@cc_on @*/ // used here and below, limits try/catch to those IE browsers that both benefit from and support it
/*@if(@_jscript_version >= 5) // prevents errors in old browsers that barf on try/catch & problems in IE if Active X disabled
try {loadXmlHttp.ie = window.ActiveXObject}catch(e){loadXmlHttp.ie = false;};
@end @*/
if (window.XMLHttpRequest && (!loadXmlHttp.ie || loadXmlHttp.re))
loadXmlHttp.xmlHttp = function(){return new XMLHttpRequest();}; // Firefox, Opera 8.0+, Safari, others, IE 7+ when live - this is the standard method
else if (/(object)|(function)/.test(typeof createRequest))
loadXmlHttp.xmlHttp = createRequest; // ICEBrowser, perhaps others
else {
loadXmlHttp.xmlHttp = null;
// Internet Explorer 5 to 6, includes IE 7+ when local //
/*@if(@_jscript_version >= 5)
try{loadXmlHttp.xmlHttp = function(){return new ActiveXObject("Msxml2.XMLHTTP");};}
catch(e){try{loadXmlHttp.xmlHttp = function(){return new ActiveXObject("Microsoft.XMLHTTP");};}catch(e){loadXmlHttp.xmlHttp = null;}}
@end @*/
}

loadXmlHttp.prototype.stateChanged = function(){
if (this.xmlHttp.readyState == 4 && (this.xmlHttp.status == 200 || !loadXmlHttp.re))
this.el.innerHTML = this.xmlHttp.responseText;
}

The usage is still the same:


new loadXmlHttp('requested_url', 'target_element_id')

But now most of the 'heavy lifting' is only done once. And I believe I corrected an error in the logic (highlighted). I haven't tested it (the whole thing) much though, so it may need some tweaking.

Oh, and this reminds me that I still hadn't responded to your question about:


var f = this;

We need a variable for the instance, here:


f.xmlHttp.onreadystatechange = function(){f.stateChanged();};

I used f because I couldn't think of anything else, and it is after all a function. And since it is required anyway, may as well use it as shorthand in the rest of the code.

jscheuer1
03-21-2009, 04:30 AM
If you are reading this, please also refer to the (my) previous post in this thread, unless you were directed here in single post view. Anyways, the current code I'm using is a bit reduced over that in my previous post, here it is:


function loadXmlHttp(url, id) {
var f = this;
if (loadXmlHttp.xmlHttp){
f.xmlHttp = loadXmlHttp.xmlHttp();
f.el = document.getElementById(id);
f.xmlHttp.open("GET", url, true);
f.xmlHttp.onreadystatechange = function(){f.stateChanged();};
f.xmlHttp.send(null);
}
else alert('Your browser does not support AJAX!'); // substitute your desired request object unsupported code here
}

loadXmlHttp.xmlHttp = null; loadXmlHttp.re = /^http/.test(window.location.href);
/*@cc_on @*/ // used here and below, limits try/catch to those IE browsers that both benefit from and support it
/*@if(@_jscript_version >= 5) // prevents errors in old browsers that barf on try/catch & problems in IE if Active X disabled
try {loadXmlHttp.ie = window.ActiveXObject}catch(e){};
@end @*/
if (window.XMLHttpRequest && (!loadXmlHttp.ie || loadXmlHttp.re))
loadXmlHttp.xmlHttp = function(){return new XMLHttpRequest();}; // Firefox, Opera 8.0+, Safari, others, IE 7+ when live - this is the standard method
else if (/(object)|(function)/.test(typeof createRequest))
loadXmlHttp.xmlHttp = createRequest; // ICEBrowser, perhaps others
else {
loadXmlHttp.xmlHttp = null;
// Internet Explorer 5 to 6, includes IE 7+ when local //
/*@if(@_jscript_version >= 5)
try{loadXmlHttp.xmlHttp = function(){return new ActiveXObject("Msxml2.XMLHTTP");};}
catch(e){try{loadXmlHttp.xmlHttp = function(){return new ActiveXObject("Microsoft.XMLHTTP");};}catch(e){}}
@end @*/
}

loadXmlHttp.prototype.stateChanged = function(){
if (this.xmlHttp.readyState == 4 && (this.xmlHttp.status == 200 || !loadXmlHttp.re))
this.el.innerHTML = this.xmlHttp.responseText;
}

Usage:


new loadXmlHttp('requested_url', 'target_element_id')