Uncaught TypeError: lang is not a function [duplicate]
Asked Answered
F

2

9

In my HTML I define the lang function in the script tag and add the "Test Fire!" button which has to call lang on click:

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>Testing Functions</title>
  <script type="text/javascript">
    function lang() {
      alert("Hello, World! It's JavaScript this time");
    }
  </script>
</head>

<body>
  <form action="">
    <input type="button" value="Test Fire!" onclick="lang();">
  </form>
</body>

</html>

However, if I click the button I get this error:

Uncaught TypeError: lang is not a function

But if I change the function name from lang to anything else this code works fine.

Furrier answered 8/7, 2016 at 22:48 Comment(11)
interesting... check this fiddle: jsfiddle.net/h4m1qcoq it calls the function through JS, which succeeds, but fails on the click.Toque
I'm interested in seeing the outcome of this one because that is an interesting issue.Toque
It seems this is a problem with the onclick attribute. It works fine assigning the onclick even via JS: document.getElementById('foo').onclick = lang.Mischievous
@SpencerWieczorek Though I did not try, I thought that would be the case here - thank you for verifying. I did find out that changing the method name doesn't help -- according to JSFiddle.Toque
Could it be a browser based issue?Toque
@RichardBarker Yes, works in IE but not Chrome.Mischievous
Check this: jsfiddle.net/cmedina/h4m1qcoq/6 It's working!Overhand
@Overhand while that does what the OP is looking to do, it fails to actually solve the issue.Toque
@SpencerWieczorek then there it is. Its chrome's implementation of the EMACS (i think its called) spec. Someone post a bug report to their tracker.Toque
@RichardBarker EMACS is something completely different. It’s called ECMAScript. It’s also not only happening in Chrome, but also in Firefox.Preglacial
Same as JS function named animate doesn't work, but with lang instead of animate.Bonbon
P
7

Consider this code:

<input type="button" value="Debugger Test" onclick="debugger;" />
<input type="button" value="Prototype Test" onclick="console.log(__proto__);" />

When you click on “Debugger Test” and open your debugger, you’ll see that there seems to be an implicit with scope wrapped around the onclick, making all the <input>’s properties accessible without needing to refer to the button.

Clicking on “Prototype Test” logs the prototype of the current scope. You’ll see that it’s the HTMLInputElement’s prototype, making all the scopable properties of this entire prototype chain available to the scope.

Interestingly, the scopable part of the prototype chain of the current HTMLDocument is included as well.

All this means that all global attributes (lang is one of them) and several others specific to buttons are overridden. E.g. value, type also wouldn’t work. Similarly, variables like createElement (from document) also wouldn’t work, but the unscopable append (from ParentNode.prototype) would.

All this is also explained in this answer to a related question about global variables clashing with window properties.


Your best bet is to use the standard way of adding event listeners: addEventListener.

<input type="button" value="Test" />
<script>
  function lang() {
    alert("Hello, World! It’s not an HTML event handler attribute this time");
  }

  document.querySelector("input").addEventListener("click", lang);
</script>
Preglacial answered 8/7, 2016 at 23:15 Comment(9)
So I'm assuming both Firefox and Chrome have this with scope, while IE does not?Mischievous
@SpencerWieczorek This seems to be the case for these three browsers. This issue is also new to me. I’m not sure whether this is a specified and documented feature… For Firefox at least, this doesn’t seem to be related to quirks mode.Preglacial
Somehow IE managed to make this code run. Any clues why so?Furrier
@Furrier Well, IE apparently does not wrap the code in the onclick in an implicit with scope as opposed to the other browsers.Preglacial
@Xufox any idea of a workaround?Toque
@RichardBarker Haven’t I written that in my answer? Use addEventListener! Or use any function name that isn’t a global attribute or any attribute or property name for the element you’re using onclick with (good luck guessing each time). Just stick to the modern standard (addEventListener) and you’ll generally have less trouble.Preglacial
Yes but I was speaking of the with issue not the event listener. that seems like a bug to me but it could be a design decision.Toque
@RichardBarker Well, this is browser-specific behavior. There doesn’t seem to be any way of overriding that.Preglacial
@RichardBarker It's very likely a design decision. Using the onclick attribute is discouraged anyways.Mischievous
O
2

There is no reason to complicate (I really do not know why it does not work), but you can use:

  • Add the alert directly in the input.

Result: https://jsfiddle.net/cmedina/h4m1qcoq/6/

or

Add listener to input

function lang() {
   alert("Hello, World! It's JavaScript this time");
}

document.getElementById('test').onclick = lang

Result: https://jsfiddle.net/cmedina/h4m1qcoq/7/

Overhand answered 8/7, 2016 at 23:16 Comment(2)
My purpose here is not to generate an alert. I just illustrated that calling "lang()" isn't working.Furrier
@Furrier then add listener to button my second option!Overhand

© 2022 - 2024 — McMap. All rights reserved.