Solution 1 :

You need to use a different name for that function.
translate() is already an existing method used for 2D Canvas drawings.

The translate() is a method of a 2D drawing context. The translate(x,y) method moves the canvas and its origin x units horizontally and y units vertically. source.

Solution 2 :

Solution

Avoid this by defining a JS event handler property with:

document.querySelector("input[type=button]").addEventListener("click", translate)
// or
jQuery('input[type="button"]').on("click", translate)

which will create a handler with a more predictable (probably global) scope. For best practice, also use event delegation.

Explanation

The lexical scope of a handler function defined as an html element attribute already has a translate property.

JS functions are bundled together with references to their surrounding state (the lexical environment). When you set an HTML attribute as a string of js code, you are implicitly defining a function within the scope of the HTML element.

Your <input> element will inherit properties from these interfaces: HTMLElement -> HTMLInputElement -> Node -> Event Target. We can check to see if any of them have a translate property:

console.log(Object.getOwnPropertyNames(EventTarget.prototype).includes("translate"))
// > false

console.log(Object.getOwnPropertyNames(Node.prototype).includes("translate"))
// > false

console.log(Object.getOwnPropertyNames(HTMLInputElement.prototype).includes("translate"))
// > false

console.log(Object.getOwnPropertyNames(HTMLElement.prototype).includes("translate"))
// > true

The HTMLElement interface includes a “translate” property, which is a Boolean value. The translate reference in your handler therefore gets resolved to that value, and you will get a TypeError telling you “translate is not a function” because you are trying to call a Boolean

More Explanation

If I run this in the Chrome DevTools console:

    const div = document.createElement("div");

    function translate() {
      console.log(".")
    };
    div.setAttribute("onclick", "translate()");

    getEventListeners(div).click[0]

I can inspect the listeners, and see the scope chain:

    listener: ƒ onclick(event)
      arguments: null
      caller: null
      length: 1
      name: "onclick"
      prototype: { constructor: ƒ }
      __proto__: ƒ()
        [[FunctionLocation]]: 
        [[Scopes]]: Scopes[4]
          0: With Block { align: "", title: "", lang: "", translate: true, dir: "", ... }
          1: With Block { location: Location, jQuery321081306834416800691: {…}, implementation: DOMImplementation, URL: "https://....com/", … }
          2: Script { div: div }
          3: Global { window: Window, self: Window, document: document, name: "", location: Location, … }
    once: false
    passive: false
    type: "click"
    useCapture: false

The first object in that scope chain list is the <div> that triggers the handler. Generally, the scope chains of functions defined in html element attributes way will be something like: (1) the call object -> (2) the HTML element -> (3) . . . stuff in between . . . -> (4) Document -> (5) Global.

When a variable is being resolved or looked up, js will go up the scope chain until it finds the definition. If you declare an un-nested function in your script the usual way, it will be a property of the global object. If anything between the global scope and the HTML element where the handler is defined has a property with the same name as your function, references to your function will be resolved to that property instead of your function.

Screenshot of DevTools comparing scopes of handlers defined as HTML attributes vs. with addEventListener()

Problem :

Keep getting an uncaught type error when I click the button that is supposed to trigger the translate function. Unsure what is causing this. I’ve tried changing the element from a button element to an input element with type button. Whatever I do I still get this error. Anyone able to help?

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta http-equiv="Content-Language" content="en-us">
    <title>Example Web Editor</title>
    <link rel="stylesheet" type="text/css" href="xtext/2.24.0/xtext-ace.css"/>
    <link rel="stylesheet" type="text/css" href="style.css"/>
    <script src="webjars/requirejs/2.3.6/require.min.js"></script>
    <script type="text/javascript">
        var baseUrl = window.location.pathname;
        var fileIndex = baseUrl.indexOf("index.html");
        if (fileIndex > 0)
            baseUrl = baseUrl.slice(0, fileIndex);
        require.config({
            baseUrl: baseUrl,
            paths: {
                "jquery": "webjars/jquery/3.5.1/jquery.min",
                "ace/ext/language_tools": "webjars/ace/1.3.3/src/ext-language_tools",
                "xtext/xtext-ace": "xtext/2.24.0/xtext-ace"
            }
        });
        require(["webjars/ace/1.3.3/src/ace"], function() {
            require(["xtext/xtext-ace"], function(xtext) {
                xtext.createEditor({
                    baseUrl: baseUrl,
                    syntaxDefinition: "xtext-resources/generated/mode-logic"
                });
            });
        });
    </script>
    
    <script>
        function translate() {
            console.log("function being triggered.");
            let req = new XMLHttpRequest();
            console.log("request created");
            req.open( "POST", "localhost:8003/translate", false);
            req.send(ace.edit('xtext-editor').getSession().getValue());
            return req.responseText;
            }
    </script>
</head>

<div class="container">
    <div class="header">
        <h1>Example LogicLang Web Editor</h1>
    </div>
    <div class="content">
        <div id="xtext-editor" data-editor-xtext-lang="logic"></div>
    </div>
</div>
<form onsubmit = "return false">
<input type="button" onclick="translate()"> Compile </input>
<button class="save-button" onclick="console.log(ace.edit('xtext-editor').getSession().getValue());"> Test </button>
</form>
</body>
</html>

Comments

Comment posted by prasanth

use different name instead of

Comment posted by Emiel Zuurbier

Are you encountering any other errors before the error you’ve presented? Sidenote, don’t use synchronous HTTP requests as they will prevent other code to run while making the request.

Comment posted by Emiel Zuurbier

The

By