2

I have got this error while running. I don't know why is it showing that the myFunction() is not defined. Is there any problem with the way the function is loaded when the button is clicked.

This is my code here so far.

indentation.xhtml

  <?xml version='1.0' encoding='UTF-8' ?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns = "http://www.w3.org/1999/xhtml"   
          xmlns:h = "http://java.sun.com/jsf/html"
          xmlns:f = "http://java.sun.com/jsf/core"
          xmlns:p="http://primefaces.org/ui">


        <h:head>
            <style type="text/css">
                .code-str     { color: #080;}  
                .code-elem    { color: #f00;}  
                .code-comment { color: #00f;}
            </style>
        </h:head>


        <h:body>

            <h:form>
                <p:inputTextarea  rows="15" cols="80" id="text1"></p:inputTextarea>
                <br/>
                <p:commandButton  type="button" value = "submit" action="indentation" onclick="myFunction()"></p:commandButton>

                <div id="demo"></div>
            </h:form>
        </h:body>


        <script type="text/javascript">
            const keywords = {
                IF: {style: "code-elem", indent: 4},
                ENDIF: {style: "code-elem", indent: -4},
                IFLISTING: {style: "code-str", indent: 4},
                ENDIFLISTING: {style: "code-str", indent: -4},
                VAR: {style: "code-comment", indent: 0},
                LISTING: {style: "code-comment", indent: 0}
            };

            window.onload = function myFunction() {
                let indent = 0;
                document.getElementById("demo").innerHTML = document.getElementById("text1").value.split(/[\r\n]+/).map(line => {
                    const oldIndent = indent;
                    line = line.trim().replace(/###([A-Z]+)(.*?)###/g, (m, keyword, arg) => {
                        const param = keywords[keyword];
                        if (!param)
                            return m;
                        indent += param.indent;
                        return `<span class="${param.style}">${m}</span>`;
                    });
                    return "&nbsp;".repeat(Math.min(indent, oldIndent)) + line;
                }).join("<br/>");
            }
        </script>
</html>

Please, can anyone help me find the problem here? After pressing the button, it should provide some color to the code.

Sonney
  • 55
  • 6
  • I've rolled back your edit folding the answer into the question. That isn't how we do things on SO. The question remains a question, and the answer(s) answer it. Questions should not be moving targets. – T.J. Crowder Jun 13 '19 at 11:30
  • okay. Thanks. :) – Sonney Jun 13 '19 at 11:53

1 Answers1

3

Your onclick-attribute-style event handler expects to find a global with the name myFunction, but when you use a named function expression like this:

window.onload = function myFunction() {
    // ...
};

the function name is not added to the scope in which that expression appears (except in old broken versions of IE).

Function declarations add to the scope, so you could use a declaration and an assignment:

function myFunction() {
    // ...
}
window.onload = myFunction;

I'd strongly recommend moving away from onxyz-attribute-style event handlers, not least because they require global functions, and the global namespace is already overcrowded and rife with conflict. Instead, wrap your code in a scoping construct (an IIFE, a module, etc.) and use modern event handling (addEventListener, etc.). Note that if you're looking up an element by id in a JSF page, the client-side ID is not the id you give the element (by default), full explanation in this question's answers. (Thank you Kukeltje for point that out to the OP in the comments.)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thanks a lot. I have made the change that you have said, but then it shows another error now. TypeError: document.getElementById(...) is null. What shall I do about that? – Sonney Jun 13 '19 at 11:26
  • 1
    @Sonney - See http://stackoverflow.com/questions/14028959/why-does-jquery-or-a-dom-method-such-as-getelementbyid-not-find-the-element – T.J. Crowder Jun 13 '19 at 11:29
  • Thank you so much for this link. It cleared some of my doubts. But since I am very new to this and don't know much about javascript. Can you please help me tell that how can I use addEventListener in this code. – Sonney Jun 13 '19 at 11:52
  • @Sonney - I can't, no, I'm not familiar with PrimeFaces. I see you have `
    ` and that the `getElementById` call is for `"demo"` and is on window load, so that tells me that for some reason that `div` isn't in the DOM as of when that call happens. I can't tell you why not, just that it isn't there. You'll need to use the devtools of your browser and debug it. Good luck!
    – T.J. Crowder Jun 13 '19 at 11:58
  • 1
    The error is on the `document.getElementByID("text1")` See https://stackoverflow.com/questions/6045307/how-can-i-know-the-id-of-a-jsf-component-so-i-can-use-in-javascript – Kukeltje Jun 13 '19 at 17:21
  • @Kukeltje Thanks for the link, I have read it. So you suggest I should use BackBean?? after reading that I have given an id to the form tag and made the required changes. But it still shows the same error. – Sonney Jun 18 '19 at 07:38
  • 1
    Effectively you have a new question. Accept the answer to this one and create a new question with a [mcve] – Kukeltje Jun 18 '19 at 07:54