JavaScript - HTMLElement In IE

There are many things that irritate me about Internet Explorer like poor CSS support and the differences JScript brings to the table and the bugs that go along with that (memory leaks, etc, etc) but recently I found yet another reason to loath developing applications for IE. HTMLElement. Mozilla and Opera have given us the ability to prototype this object which greatly simplifies extending the document object model (DOM) however IE (also Safari) decided to keep this object hidden and untouchable. Why? Good question! Who knows what goes on in the minds of these “brilliant” programmers or, probably, more fairly, the project managers that oversee the development.

Anyways, compaining and speculation aside, I have come up with a method to work around these short comings and provide a way to extend the DOM. Enjoy!

JavaScript

var DOMElement =
{
	extend: function(name,fn)
	{
		if(!document.all)
			eval("HTMLElement.prototype." + name + " = fn");
		else
		{
			//
			//	IE doesn't allow access to HTMLElement
			//	so we need to override
			//	*document.createElement
			//	*document.getElementById
			//	*document.getElementsByTagName
			//

			//take a copy of
			//document.createElement
			var _createElement = document.createElement;

			//override document.createElement
			document.createElement = function(tag)
			{
				var _elem = _createElement(tag);
				eval("_elem." + name + " = fn");
				return _elem;
			}

			//take copy of
			//document.getElementById
			var _getElementById = document.getElementById;

			//override document.getElementById
			document.getElementById = function(id)
			{
				var _elem = _getElementById(id);
				eval("_elem." + name + " = fn");
				return _elem;
			}

			//take copy of
			//document.getElementsByTagName
			var _getElementsByTagName = document.getElementsByTagName;

			//override document.getElementsByTagName
			document.getElementsByTagName = function(tag)
			{
				var _arr = _getElementsByTagName(tag);
				for(var _elem=0;_elem<_arr.length;_elem++)
					eval("_arr[_elem]." + name + " = fn");
				return _arr;
			}
		}
	}
};

HTML

<html>
<head>
	<script type="text/javascript" src="DOMElement.js"></script>
	<script type="text/javascript">

		DOMElement.extend("foo",function(){alert('bar')});
		DOMElement.extend("about","DOMElement v0.1")
		DOMElement.extend("contents",function(){return this.innerHTML})
		var elem = document.createElement("div");
		elem.foo();

		onload = function()
		{
			var elem2 = document.getElementById("myDiv");
			alert(elem2.about);

			var divs = document.getElementsByTagName("div");
			for(var i=0;i<divs.length;i++)
				alert(divs[i].contents())
		}

	</script>
</head>
<body>

	<div id="myDiv">hi</div>
	<div id="div2">there</div>

</body>
</html>

16 comments on this post

Sirio says:
Aug 17, 2007 - 07:08:03

Has been this thing tested? it returns a bunch of errors both in IE and Mozilla.

Justin says:
Aug 17, 2007 - 08:08:56

Sirio,

The following, cut and pasted form the article examples works perfectly in IE and Firefox.

<html>
<head>
	<script type="text/javascript" src="DOMElement.js"></script>
	<script type="text/javascript">

		var DOMElement =
		{
			extend: function(name,fn)
			{
				if(!document.all)
					eval("HTMLElement.prototype." + name + " = fn");
				else
				{
					//
					//	IE doesn't allow access to HTMLElement
					//	so we need to override
					//	*document.createElement
					//	*document.getElementById
					//	*document.getElementsByTagName
					//

					//take a copy of
					//document.createElement
					var _createElement = document.createElement;

					//override document.createElement
					document.createElement = function(tag)
					{
						var _elem = _createElement(tag);
						eval("_elem." + name + " = fn");
						return _elem;
					}

					//take copy of
					//document.getElementById
					var _getElementById = document.getElementById;

					//override document.getElementById
					document.getElementById = function(id)
					{
						var _elem = _getElementById(id);
						eval("_elem." + name + " = fn");
						return _elem;
					}

					//take copy of
					//document.getElementsByTagName
					var _getElementsByTagName = document.getElementsByTagName;

					//override document.getElementsByTagName
					document.getElementsByTagName = function(tag)
					{
						var _arr = _getElementsByTagName(tag);
						for(var _elem=0;_elem<_arr.length;_elem++)
							eval("_arr[_elem]." + name + " = fn");
						return _arr;
					}
				}
			}
		};

		DOMElement.extend("foo",function(){alert('bar')});
		DOMElement.extend("about","DOMElement v0.1")
		DOMElement.extend("contents",function(){return this.innerHTML})
		var elem = document.createElement("div");
		elem.foo();

		onload = function()
		{
			var elem2 = document.getElementById("myDiv");
			alert(elem2.about);

			var divs = document.getElementsByTagName("div");
			for(var i=0;i<divs.length;i++)
				alert(divs[i].contents())
		}

	</script>
</head>
<body>

	<div id="myDiv">hi</div>
	<div id="div2">there</div>

</body>
</html>
L.law.liet says:
Aug 30, 2007 - 02:08:12

How to make DOMElement for Event Handler..??
ex) e.srcElement

Bob says:
Dec 29, 2007 - 06:12:21

This is pretty ass smart

Jason says:
Apr 22, 2008 - 07:04:27

This was a huge help in implementing the FBJS (Facebook JavaScript) support for Ringside Networks. Just wanted to say thanks!

May 16, 2008 - 11:05:12

Thank you so much! I combined your code with a .htc to make sure that the “this” keyword worked always.


HTML:
<a href="#" onlick="this.remove();return false>Remove</a>

CSS:
*{behavior:common.htc}

In the HTC:
this.remove = function(){
var el=(typeof this==='string')?document.getElementById(this):this;
el.parentNode.removeChild(el);
}

Charlie says:
Jun 30, 2008 - 06:06:58

Actually you can find an unobtrusive inplementation of the HTMLElement at http://www.jslab.dk/epe.introduction.php

Anthony Alexander says:
Aug 11, 2008 - 03:08:44

omg. i’d say about 75% of all ‘Ajax’ code written is to cover holes left by browsers and obvious neglected features. i wonder how long the standards guys are going to let the browser market be dominated by a plugin!

Aug 22, 2008 - 02:08:58

The use of eval is completely unnecessary.
If you used a for-in loop, an object literal as the function parameter, and hash notation, you could reduce this script to one third its size.

Lauri Kolmonen says:
Sep 25, 2008 - 02:09:48

I had some problems with extending HTMLElements in IE. I tried various approaches unsuccessfully and after some research I found out that Prototype Javascript library has nice and browser compatible tools for extending HTML elements (http://www.prototypejs.org/learn/extensions)

none says:
Sep 26, 2008 - 03:09:31

–.–”

you should use:

_elem[name] = fn;

instead of that orrible eval(”_elem.” + name …);

Lon5 says:
Oct 7, 2008 - 12:10:04

Thanks from China!
This is exactly what I need!

ami ladh says:
Feb 7, 2009 - 12:02:07

You’re the man!

Josh says:
Jun 24, 2009 - 04:06:32

Very clever script, thanks heaps, helped me a ton.