Search code examples
javascripthtmldomecmascript-6ecmascript-5

Can we overwrite Javascript DOM object prototype properties?


I have been looking for a way to permanently change the HTMLFormElement Javascript object's 'onsubmit' behavior. Let's suppose that one of my Javascript would contain the following code:

HTMLFormElement.prototype.onsubmit = function () {
    this.submit();
    // Make sure that you can only submit once.
    this.onsubmit = function () {
        return false;
    };
    return false;
};

The idea would be to simply prevent double submits on all forms of the document. I wasn't able to figure out how to do this since the above example is not working.

Is there a way to achieve this without looping through all existing HTMLElements after the document is loaded? A way which would be compatible with some older browser and also persist the behavior if you create new form elements using other scripts. (Vanilla JS only please)


Solution

  • Can we overwrite Javascript DOM object prototype properties?

    Although the javascript spec cuts host objects a lot of slack in violating normal javascript behavior Object.defineProperty(HTMLFormElement.prototype, "onsubmit", {get: () => {return false;}}) does work. "Work" as in setting a getter on the prototype.

    But it's not actually what you want. That's just replacing the getter/setter functionality. There is no guarantee that the browser goes through the javascript inheritance chain to retrieve the handler for the current form.

    Either because it bypasses javascript by directly looking at some underlying native properties or because it doesn't have to look at the prototype at all and looks at an instance property of the form itself.

    Messing with prototypes is rarely a good idea if you don't know how and when individual properties are actually used by the target class.

    Another thing: the getter/setter actually is on HTMLElement.prototype, not HTMLFormElement.prototype. At least that's where it is in Firefox. You should at least inspect the inheritance chain before trying to mess with it ;)

    The idea would be to simply prevent double submits on all forms of the document.

    Instead of messing with prototypes you can simply install a capturing event listener on the document.

    capturing because it happens earlier and is less likely to be intercepted via stopPropagation without canceling the default action, which would be the form submission this case.

    document.addEventListener("submit", (e) => {e.preventDefault();}, true);