最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - An input in a form named 'action' overrides the form's action property. Is this a bug? - St

matteradmin3PV0评论

I have a form marked up as

<form class="form1" method="post" action="form1.php" style="width:405px">

Ordinarily, I could access the action of the form in javascript by referring to the .action of the form object, for example

document.forms[0].action

which would return the value

form1.php

However, if I have, as a ponent of the form, an item named "action", this "action" bees the content of the form's action. That is, if the form markup contains, for example,

<input name="action" type="hidden" value="check" />

Then

document.forms[0].action

returns the value

<input name="action" type="hidden" value="check" />

Now, I did work out how to get around this: by using

document.forms[0].getAttribute("action")

However, it's a nasty gotcha that confused me for too long. Is this a bug? A known gotcha of DOM management? Or should I just get into the habit of using .getAttribute()?

I have a form marked up as

<form class="form1" method="post" action="form1.php" style="width:405px">

Ordinarily, I could access the action of the form in javascript by referring to the .action of the form object, for example

document.forms[0].action

which would return the value

form1.php

However, if I have, as a ponent of the form, an item named "action", this "action" bees the content of the form's action. That is, if the form markup contains, for example,

<input name="action" type="hidden" value="check" />

Then

document.forms[0].action

returns the value

<input name="action" type="hidden" value="check" />

Now, I did work out how to get around this: by using

document.forms[0].getAttribute("action")

However, it's a nasty gotcha that confused me for too long. Is this a bug? A known gotcha of DOM management? Or should I just get into the habit of using .getAttribute()?

Share edited Aug 7, 2013 at 15:50 Charles 51.4k13 gold badges106 silver badges144 bronze badges asked Aug 7, 2013 at 10:12 bugmagnetbugmagnet 7,7798 gold badges72 silver badges140 bronze badges 1
  • 1 Not a bug, the browser is emulating IE behaviour which started form[elementname] style - correct would be form.elements[elementname]. However I had expected the attribute to shadow the input… – Bergi Commented Aug 7, 2013 at 10:24
Add a ment  | 

3 Answers 3

Reset to default 7

I would not call this a bug. This effect occurs, because attributes can be read by using element.attributename and named inputs inside a form can be accessed in the same way, formelement.inputname. If there is an attribute and an input with the same name, there is no guarantee which one will be used. It probably behaves differently in different browsers.

I personally use getAttribute if I am reading a known attribute that was included in the markup or added using setAttribute in JavaScript. For dynamic values like, for example, the checked attribute of a checkbox, I don't use getAttribute. But this is more a question of personal preference, I guess.

I am fighting this behaviour at the moment too (7 years later!)

It is very hacky, but you are able to access and call the action getter directly by using the following.

Object.getOwnPropertyDescriptor(HTMLFormElement.prototype, 'action').get.call(document.forms[0]);

Having encountered this for a number of different form attrs, I finally worked up a general solution based on @threenplusone's answer.

The following code creates a safeForm() function that wraps any Forms in a Proxy object which transparently "unmasks" any form properties that have been hidden ("id", "name", "action", etc). All other values are returned as-is.


// get property descriptor from wherever in chain
function getPropertyDescriptor (obj, name) {
    let desc;
    while(obj && !(desc = Object.getOwnPropertyDescriptor(obj, name))) {
        obj = Object.getPrototypeOf(obj);
    }
    return desc;
}

// helpers for safeForm()
const isFormProxy = Symbol("isFormProxy"),
    formHandler = {
        get(form, prop) {
            if (prop === isFormProxy) return true;  // helper to detect proxy
            let value = form[prop];
            if (value instanceof HTMLElement && value.name === prop){
                let desc = getPropertyDescriptor(HTMLFormElement.prototype, prop);
                if(desc){
                    return desc.get.call(form);
                }
                // NOTE: ment out next line to include elements                 
                //       that aren't shadowing a form attribute.                 
                return;
            }
            return value;
        },
        set(form, prop, value){
            if(prop === isFormProxy) return;
            form[prop] = value;
        },
    };


// frontend function
function safeForm (elem){
     if(elem instanceof HTMLFormElement && !elem[isFormProxy]){
         return new Proxy(elem, formHandler);
     }
     return elem;
}

Articles related to this article

Post a comment

comment list (0)

  1. No comments so far