Thursday, April 21, 2005

DOM 0 with XHTML caveat

Here's an interesting gotcha, unearthed from Bobby van der Sluis' popular article on JavaScript good practices that's making the rounds: when you serve an XHTML document as application/xhtml+xml, the good old DOM Level 0 collections like document.images and document.forms go bye-bye, at least in Mozilla-based browsers.

I'm okay with this, but I love me some backwards-compatible DOM 0, especially when I know exactly which element I need to access via script. Luckily, it's perfectly okay to serve XHTML 1.0 as "HTML compatible" text/html. It's when you start serving XHTML 1.1 as text/html that people start yelling and pointing.

Here's the Bugzilla discussion of this behavior.

10 Comments:

At 1:06 PM, Anonymous Anonymous said...

Personally, I never use the DOM0 functions anyway; document.getElementsByTagName('form') is the same as document.forms, and works everywhere, so I never even think to use the old way. Is there any advantage to doing so? I can't think of one...

sil

 
At 3:14 PM, Blogger scottandrew said...

1. Backward compatibility.
2. Shorter code.
3. No need to iterate thru a collection.

 
At 8:05 PM, Anonymous Anonymous said...

Those collections are available in DOM Level 2, but they're part of the HTML DOM, thus not available when serving a document as XML.

To add to Scott's reasons for using those functions, they are also sometimes faster than their DOM core counterparts, especially in IE.

 
At 12:36 AM, Anonymous Anonymous said...

"Luckily, it's perfectly okay to serve XHTML 1.0 as "HTML compatible" text/html."

Hixie has a few things to say about just how okay that is: http://www.hixie.ch/advocacy/xhtml
(To sum it up: not at all.)

 
At 6:34 AM, Blogger Marty said...

Anon, that link makes my head hurt. Almost enough to make me want to return to the food service industry! Ugh.

(tag soup rules)

 
At 8:40 AM, Blogger scottandrew said...

This comment has been removed by a blog administrator.

 
At 8:56 AM, Blogger scottandrew said...

I've seen that Hixie screed invoked a kabillion times, but it simply doesn't change the fact that it's hunky-dory to serve HTML-compatible XHTML 1.0 as text/html:

http://www.w3.org/TR/xhtml-media-types/#summary

Earlier in the same doc:

"XHTML Documents which follow the guidelines set forth in Appendix C, 'HTML Compatibility Guidelines' may be labeled with the Internet Media Type "text/html", as they are compatible with most HTML browsers."

Of course, YOU are welcome to take Hixie's advice and/or serve it any way you want. I don't particularly care.

This blog is about JS in the real world, not mime-type evangelism. Can we get back to talking about JS now?

 
At 12:56 PM, Anonymous Anonymous said...

It seems to me that if you suspect this is going to be an issue in your code you can add these back in easily, by putting in something like:

if(!document.images) { var images = document.getElementsByTagName("img") };
if(!document.forms) { var forms = document.getElementsByTagName("forms") };

The only hard part is where to add it. Obviously it needs the entire page to load or the collections will be incomplete (or entirely empty) but before any other functions that might use it run. But I think in most situations, it (or something like it) should work to give you your backwards compatibility.

Also, man, it bums me out that Blogger won't allow <code> or any other similar code-type tags in their comments. Weak, Blogger, weak!

 
At 2:39 PM, Blogger scottandrew said...

Mark: your solution is similar to Jeremy's, but it doesn't allow me to go straight to the element I want. For example:

var f = document.forms["signupForm"];

If I were to use getElementsByTagName("form") here instead, I'd have to iterate over the resulting collection to get to the FORM element I want. The old-school method seems much simpler.

Sure, you can structure your faux document.forms to do this, but you'd be reinventing the wheel, no?

 
At 10:59 AM, Anonymous Anonymous said...

Hey Jeremy, what is this:
As for backwards compat:
document.__defineGetter__('images', function(){return document.getElementsByTagName('img')});

Of course, that works against shorter code...


the defineGetter thing. What exactly does it do?

 

Post a Comment

<< Home