Overriding DOM Methods
This article is an analysis of how to add or override methods on HTML DOM objects.
How can I add my own methods to DOM objects?
All the major browsers allow you to extend HTML DOM objects (documents, elements, events, etc) with your own methods. For this purpose you can treat DOM objects as Javascript objects so, for example, do this:
var form = document.getElementsByTagName("form")[0]; form.alertURL = function() { alert(this.action); // same as alert(form.action) }
In the method this
refers to the DOM object the method is attached to (in this case a form element).
Recent versions of Firefox, Safari and Opera also enable you to add methods to DOM prototypes, meaning all DOM objects of a certain type can be extended at once. For example
HTMLFormElement.prototype.alertURL = function() { alert(this.action); }
is the equivalent of
Array.forEach( document.getElementsByTagName("form"), function(form) { form.alertURL = function() { alert(this.action); } } });
Actually it isn't quite the same - if you dynamically add a <form>
element to the page then
the first approach (using HTMLFormElement.prototype) will automatically attach the method where the second approach leaves it up to you.
- DOM prototypes are available in Firefox, Safari 3+ and Opera 8+
- DOM prototypes aren't available in IE6 and IE7, but will be in IE8.
- It is also possible to access DOM prototypes on Safari-2 and earlier.
What if I want to override built-in DOM methods?
This is exactly the same as extending DOM objects with your own method. If you don't want to allow programmable submission of a form you could use
form.submit = function() { alert("Preventing attempted form submission."); }
- Browsers that provide DOM prototypes also allow you to override methods on the prototype.
- I can't recall any instances where overriding built-in DOM methods doesn't work, but you should test anyway.
What if I want to call the built-in DOM method from my override?
This is the point at which the browsers really diverge.
Firefox, Opera and Safari-3 allow you to call the method on the DOM prototype
(if you are overriding a method on the object).
You need to call the prototype method with .call(this)
or more generically .apply(this, arguments)
so that the method is executed in the context of the DOM object.
For example, if you want the user to confirm before allowing programmable submission of a form:
form.submit = function() { if (!confirm("Automatic submission of this form has been requested. You okay with that?")) return; HTMLFormElement.prototype.submit.apply(this, arguments); }
- This doesn't seem to work on Firefox when calling
Event.prototype.method()
from anevent.method()
override.
Alternatively you could save a reference to the original DOM method and call that from the overriding method. e.g.
form._submit = form.submit; // saved reference form.submit = function() { if (!confirm("Automatic submission of this form has been requested. You okay with that?")) return; this._submit.apply(this, arguments); }
In this example the reference is saved on the DOM object itself, meaning that it could be called as regular method:
form._submit = form.submit; // saved reference form.submit = function() { if (!confirm("Automatic submission of this form has been requested. You okay with that?")) return; this._submit(); }
This technique can also be used on DOM prototypes, e.g.
HTMLFormElement.prototype._submit = HTMLFormElement.prototype.submit; HTMLFormElement.prototype.submit = function() { if (!confirm("Automatic submission of this form has been requested. You okay with that?")) return; this._submit(); }
The down-side to this is that you lose the ability to just pass on the arguments array to the original DOM method.
IE6 (and presumably other versions of IE) implement the methods on DOM objects as something like
bound methods -
you could store a reference to the DOM method anywhere, even in a variable or on another DOM object,
and when the method is called it will still execute in the context of the original DOM object.
In fact, IE DOM methods aren't even Javascript functions so, for instance, calling them with .call()
or .apply()
will throw an error.
So the only solution on IE will look something like this:
form._submit = form.submit; // saved reference form.submit = function() { if (!confirm("Automatic submission of this form has been requested. You okay with that?")) return; this._submit(); }
Safari-2 (if you need to support it) implements methods on DOM objects differently again. They are neither normal Javascript methods (like Firefox, Safari-3, Opera) or bound-methods (like IE). However, a little experimentation reveals that if you save a reference to a DOM method on the object itself you can still call it as a normal method of the object.
form._submit = form.submit; // saved reference form.submit = function() { if (!confirm("Automatic submission of this form has been requested. You okay with that?")) return; this._submit(); }
But is there a simple cross-browser way to override DOM methods while still allowing the original methods to be called?
Yes. Despite differing implementations of DOM methods there is one solution that does work in all the leading browsers.
If you copy the original DOM method on the original DOM object with a different method name then the copy can be called in the same way as the original method, even if the original method is overridden.
form._submit = form.submit; // saved reference form.submit = function() { if (!confirm("Automatic submission of this form has been requested. You okay with that?")) return; this._submit(); }
Although this approach works cross-browser, it would be preferrable to use DOM prototypes by default and fallback to modifying DOM objects when the prototypes aren't available.
How do I override methods on XML DOM objects in Internet Explorer?
Ummm... I don't think you can do that.
How do I add properties to DOM objects? How do I override built-in properties?
That's a question for another time.