1

Having this code

<script>
function faul() { alert("faul"); }
</script>

<form>
  <button onclick="faul()">action</button>
  <input name="faul" required>
</form>

clicking the button results in faul is not a function, but when the button is outside the form or when it is called as onclick="window.faul()" the function is called.

Please explain the conflict.

Jan Turoň
  • 31,451
  • 23
  • 125
  • 169
  • It's an old quirk, IE used to add form element names to the global object, and today other browsers do as well, so ` – adeneo May 05 '19 at 14:11
  • 1
    I disagree with the "duplicate", as in this case it's explicitly about the `name` attribute, not the `id` attribute, and there are differences regarding global scope vs form scope. – Constantin Groß May 05 '19 at 14:15
  • @adaneo in my Chrome, when I call `window.faul()` the function is called, while just `faul()` causes an error since it is hidden by the named element. Also could you please unduplicate the flag since the linked question is about ID attribute and this about NAME attribute and the behavior is almost the same, but not entirely identical. I want to ask and I cannot get answer because of the hasty close :( – Jan Turoň May 05 '19 at 16:29

1 Answers1

2

If you do a console.log(faul) in the click handler, you'll see that faul is a global reference to the input with the same name.

The cause is that for historic reasons, (most if not all) browsers pollute the scope that form elements' inline event handlers are run in by making any element with a name attribute available as a reference by that name. The same is true for any element with an id attribute, but in global scope, by the way (demonstrated below).

Adding the handler using addEventListener() instead of an inline attribute will circumvent this issue (demonstrated below as well).

document.querySelector('form button').addEventListener('click', function() {
  console.log('from addEventListener handler: ', faul);
});
<script>
function faul() { alert("faul"); }
</script>

<form>
  <button onclick="console.log('from inline handler:', faul)">log faul</button>
  <button onclick="console.log(faul2)">log faul2</button>
  <input name="faul" required>
  <div id="faul2"></div>
</form>
Constantin Groß
  • 10,719
  • 4
  • 24
  • 50
  • What still confuses me, that from inline handler if the button is outside the form, it correctly call the faul function. Could you also explain why call by `window.faul()` works? I know about `formElement.faul` access, but how the heck it conflicts with global name? – Jan Turoň May 05 '19 at 16:20
  • Named elements are only available inside the form scope, that's why when the button is located outside, it references the global reference to the function with the same name, as does explicitly calling `window.faul` (in browser context, `window` is also the global scope). – Constantin Groß May 05 '19 at 16:55