1

The onblur attribute is not working for form validation on an html page when I try to use a function in an external javascript file while the onclick attribute works. So, only the result function from the JS file is working. Please help me know why. Below is my html and js file. HTML file:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Maintenance request</title>
        <script type="text/javascript" src="MaintainScript.js></script>
        <link rel="stylesheet" type="text/css" href="maintainStyle.css">    
    </head>
    <body>
        <div id="banner"><h1 style="color:#FFFFFF;">Housing Maintenance Request</h1></div>
        <form>
        <table>
        <tr>
         <td>Name:</td><td><input type="text" id="name" onblur="name();"><span id="msg1"><span></td>
        </tr>
        <tr>
        <td>Phone:</td><td><input onblur="phone();" type="text" id="phone" placeholder="xxx-xxx-xxxx"><span id="msg2"><span></td>
        </tr>
        <tr>
        <td>Student ID:</td><td><input onblur="id();" type="number" id="Student ID"><span id="msg3"><span></td>
        </tr>
        <tr>
        <td>Email:</td><td><input onblur="email();" type="text" id="Email" placeholder="email@mail.com"><span id="msg4"><span></td>
        </tr>
        <tr>
        <td>Type of request:</td>
        <td><select>
            <option>A/C</option>
            <option>Door Lock</option>
            <option>Mirror</option>
            <option>Shower</option>
            <option>Light out</option>
            <option>Room change</option>
            <option>Pest issue</option>
            <option>Mold</option>
        </select></td>
        </tr>
        <tr>
        <td>Room/Apt/Suite:</td><td><input onblur="room();" type="text" id="room"><span id="msg3"></span></td>
        </tr>
        </table>
        <div class="comments"><center>Describe the problem</center><br><textarea cols=145 rows=7></textarea></div>
        <div class="submit"><input type="button" onclick="result();" value="SUBMIT"></div>
        <span id="end"></span>  
    </form>
</body>

And then the JS file:

    function name(){
        var response = document.getElementById("name").value;
        if(response.length == 0){
            document.getElementById("msg1").style.color = "Red";
            document.getElementById("msg1").innerHTML = " You did not provide name";
        }
        else{
            document.getElementById("msg1").style.color = "Green";
            document.getElementById("msg1").innerHTML = "<strong> Valid</strong>";
        }
    }
    function phone(){
        var response = document.getElementById("phone").value;
        var pattern = /^d{3}-d{3}-d{4}$/;
        if(pattern.test(response)){
            document.getElementById("msg2").style.color = "Red";
            document.getElementById("msg2").innerHTML = " Provide number in xxx-xxx-xxxx format";
        }
        else{
            document.getElementById("msg2").style.color = "Green";
            document.getElementById("msg2").innerHTML = "<strong> Valid</strong>";
        }
    }
    function id(){
        var response = document.getElementById("id").value;
        if(response.length == 0){
             document.getElementById("msg3").style.color = "Red";
             document.getElementById("msg3").innerHTML = " You did not provide a seven-digit id";
    }
    else{
        document.getElementById("msg3").style.color = "Green";
        document.getElementById("msg3").innerHTML = "<strong> Valid</strong>";
    }
}
function email(){
    var emailInput = document.getElementById("email").value;
    var emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (emailPattern.test(emailInput)){
        document.getElementById("msg4").style.color = "Green";
        document.getElementById("msg4").innerHTML = "<strong> Valid</strong>";
        return (true);
    }
    else{
        document.getElementById("msg4").style.color = "Red";
        document.getElementById("msg4").innerHTML = " Invalid Email";
        return (false);
    }
}
function room(){
    var response = document.getElementById("room").value;
    var pattern = /^d{3}-s{1}$/;
    if(patttern.test(response)){
        document.getElementById("msg5").style.color = "Red";
        document.getElementById("msg5").innerHTML = " You did not provide accurate room information";
        return(true);
    }
    else{
        document.getElementById("msg5").style.color = "Green";
        document.getElementById("msg5").innerHTML = "<strong> Valid</strong>";
        return(false);
    }
}
function result(){
    document.getElementById("end").innerHTML = "<center>Your request has been recorded. Please stay patient as the maintenance team prepares to work on it. Thanks.</center>";
} 
  • 2
    Try putting ` – Zak Jul 24 '17 at 21:54
  • https://stackoverflow.com/questions/2105327/should-jquery-code-go-in-header-or-footer – Zak Jul 24 '17 at 21:58
  • @Zak: There's no indication in the code above to suggest that doing that is necessary. The automatic globals are only created if there isn't already a global by the given name. Yes, it's generally best practice to put it at the end of `body`, but that's not the problem above. – T.J. Crowder Jul 24 '17 at 21:59
  • Depending on the browser used .. The DOM "could" load incorrectly. Best to get practices corrected FIRST, then work on the "problem" if it still exists.... Hence I posted a comment, and not an answer ;) – Zak Jul 24 '17 at 22:02
  • @Zak: :-) There is that. – T.J. Crowder Jul 24 '17 at 22:04
  • Use `var pre = onload; onload = function(){if(pre)pre(); /*put your code here */}`. – StackSlave Jul 24 '17 at 22:10
  • @PHPglue: Goodness gracious no. `onload` is far too late. – T.J. Crowder Jul 24 '17 at 22:12
  • Nope. You want the whole market, you're going to need IE8. – StackSlave Jul 24 '17 at 22:13
  • @PHPglue: So? Script at bottom, problem solved. Next problem please. – T.J. Crowder Jul 24 '17 at 22:14
  • Some *(very few)* Browsers will view the `` as undefined, since the ` – StackSlave Jul 24 '17 at 22:17
  • @PHPglue: Nope, someone's been feeding you FUD. :-) I've been using it for 10 years on all versions of IE (including 6), Chrome, Firefox, Konqueror, Safari, iOS Safari, Midori, ... YUI's guidelines have been suggesting it for even longer. – T.J. Crowder Jul 24 '17 at 22:20
  • No, I was working on something, using a Book that told me to put my ` – StackSlave Jul 24 '17 at 22:23
  • @PHPglue: Sorry, no. :-) Extraordinary claims require extraordinary evidence. Details / citation / proof of concept needed. – T.J. Crowder Jul 24 '17 at 22:24

1 Answers1

1

There are several good reasons not to use onxyz-attribute-style event handlers. One of the many good reasons is that they run in an environment which is even more crowded with identifiers than the global environment — and that's saying something. The code is run as though it were in several with blocks including all of the properties of the element the onxyz-attribute appears on, its form, and the document (and then of course there are globals). The identifiers added to the scope by those (effective) with blocks have higher precedence than your global functions.

So for instance, in that environment, the name and id identifiers will resolve to the name and id properties of the element, not your global name and id functions. You can prove that to yourself here:

<script>
// (This is here rather than in the script pane
// because Stack Snippets correctly put the script
// *after* the HTML; want to match OP's question)
function name() {
}
function id() {
}
</script>
<div>Focus the field below, then unfocus it:</div>
<input type="text" id="foo" onblur="console.log('name = [' + name + '], id = [' + id + ']');">

Instead:

  1. Put all your code in a scoping function so you're not creating a bunch of global functions.

  2. Hook up your handlers using modern event handling, perhaps associating them by name or by data-* attribute.

  3. Put your script at the end of the page so the elements are there when it runs (this is important for Step&nbsp2).

For instance, perhaps your phone field might look like this:

<input data-validate="phone" type="text" id="phone" placeholder="xxx-xxx-xxxx">

and your script might look like this:

(function() { // The beginning of the scoping function
    var validators = {
        phone: function phone() {
            // ....
        }
        // ...and the others...
    };

    Array.prototype.forEach.call(document.querySelectorAll("input[data-validate]"), function(element) {
        var vname = element.getAttribute("data-validate");
        var validator = validators[vname];
        if (validator) {
            element.addEventListener("blur", validator, false);
        } else if (typeof console !== "undefined" && console.error) {
            console.error("Unknown data-validate value '" + vname + "'", element);
        }
    });
})();         // The end of the scoping function

(Using workarounds like this if you need to support old IE which doesn't have addEventListener.)

Example:

(function() { // The beginning of the scoping function
    var validators = {
        phone: function phone() {
            console.log("Phone validation triggered");
        }
        // ...and the others...
    };

    Array.prototype.forEach.call(document.querySelectorAll("input[data-validate]"), function(element) {
        var vname = element.getAttribute("data-validate");
        var validator = validators[vname];
        if (validator) {
            element.addEventListener("blur", validator, false);
        } else if (typeof console !== "undefined" && console.error) {
            console.error("Unknown data-validate value '" + vname + "'", element);
        }
    });
})();         // The end of the scoping function
<div>Focus the field below, then unfocus it.</div>
<input data-validate="phone" type="text" id="phone" placeholder="xxx-xxx-xxxx">

Or, of course, use one of the many fine form validation libraries out there which have already been thoroughly designed and debugged.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Other things like alert and prompt do work when I assign them to the onblur, but for some reason, it is still refusing to use the functions in the external JS file. I tried invoking the validation checks by including in the function invoked by the onclick attribute of the submit button. It now seems as if the checks don't work themselves. Thanks to everyone involved here in the chaos though! – Sanjiv Pradhanang Jul 25 '17 at 03:30
  • @Sanjiv: Right -- because it just so happens there is no `alert` or `prompt` property on the element, form, or document. Not so `name` or `id` (at least). – T.J. Crowder Jul 25 '17 at 06:35