Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript Form Validation: understanding function call

I am a total newbie to JavaScript, trying to find my way on form validation. I have been reading books as well as online tutorials and I found the following code online that is, in my opinion, very elegant and maintainable. Unfortunately, my skills in JavaScript are not good enough to understand everything. I am here to ask your help to understand the different functions defined.

I would like also to call the InstantValidation function on an event (onSubmit event) calling it in an independent .js file (based on event listener), so might you please also help me to call the function appropriately?

Here is the code:

<html>

<body>

    <form id="myform" action="#" method="get">
        <fieldset>

            <legend><strong>Add your comment</strong></legend>

            <p>
                <label for="author">Name <abbr title="Required">*</abbr></label>
                <input name="author" id="author" value="" 
                    required="required" aria-required="true" 
                    pattern="^([- \w\d\u00c0-\u024f]+)$"
                    title="Your name (no special characters, diacritics are okay)"
                    type="text" spellcheck="false" size="20" />
            </p>

            <p>
                <label for="email">Email <abbr title="Required">*</abbr></label>
                <input name="email" id="email" value=""
                    required="required" aria-required="true" 
                    pattern="^(([-\w\d]+)(\.[-\w\d]+)*@([-\w\d]+)(\.[-\w\d]+)*(\.([a-zA-Z]{2,5}|[\d]{1,3})){1,2})$"
                    title="Your email address"
                    type="email" spellcheck="false" size="30" />
            </p>

            <p>
                <label for="website">Website</label>
                <input name="website" id="website" value=""
                    pattern="^(http[s]?:\/\/)?([-\w\d]+)(\.[-\w\d]+)*(\.([a-zA-Z]{2,5}|[\d]{1,3})){1,2}(\/([-~%\.\(\)\w\d]*\/*)*(#[-\w\d]+)?)?$"
                    title="Your website address"
                    type="url" spellcheck="false" size="30" />
            </p>

            <p>
                <label for="text">Comment <abbr title="Required">*</abbr></label>
                <textarea name="text" id="text" 
                    required="required" aria-required="true" 
                    title="Your comment" 
                    spellcheck="true" cols="40" rows="10"></textarea>

            </p>

        </fieldset>
        <fieldset>

            <button name="preview" type="submit">Preview</button>
            <button name="save" type="submit">Submit Comment</button>

        </fieldset>

    </form>



    <script type="text/javascript">
    (function()
    {

        //add event construct for modern browsers or IE
        //which fires the callback with a pre-converted target reference
        function addEvent(node, type, callback)
        {
            if(node.addEventListener)
            {
                node.addEventListener(type, function(e)
                {
                    callback(e, e.target);

                }, false);
            }
            else if(node.attachEvent)
            {
                node.attachEvent('on' + type, function(e)
                {
                    callback(e, e.srcElement);
                });
            }
        }


        //identify whether a field should be validated
        //ie. true if the field is neither readonly nor disabled, 
        //and has either "pattern", "required" or "aria-invalid"
        function shouldBeValidated(field)
        {
            return (
                !(field.getAttribute('readonly') || field.readonly)
                &&
                !(field.getAttribute('disabled') || field.disabled)
                &&
                (
                    field.getAttribute('pattern')
                    ||
                    field.getAttribute('required')
                )
            ); 
        }


        //field testing and validation function
        function instantValidation(field)
        {
            //if the field should be validated
            if(shouldBeValidated(field))
            {
                //the field is invalid if: 
                //it's required but the value is empty 
                //it has a pattern but the (non-empty) value doesn't pass
                var invalid = 
                (
                    (field.getAttribute('required') && !field.value)
                    ||
                    (
                        field.getAttribute('pattern') 
                        && 
                        field.value 
                        && 
                        !new RegExp(field.getAttribute('pattern')).test(field.value)
                    )
                );

                //add or remove the attribute is indicated by 
                //the invalid flag and the current attribute state
                if(!invalid && field.getAttribute('aria-invalid'))
                {
                    field.removeAttribute('aria-invalid');
                }
                else if(invalid && !field.getAttribute('aria-invalid'))
                {
                    field.setAttribute('aria-invalid', 'true');
                }
            }
        }


        //now bind a delegated change event 
        //== THIS FAILS IN INTERNET EXPLORER <= 8 ==//
        //addEvent(document, 'change', function(e, target) 
        //{ 
        //  instantValidation(target); 
        //});


        //now bind a change event to each applicable for field
        var fields = [
            document.getElementsByTagName('input'), 
            document.getElementsByTagName('textarea')
            ];
        for(var a = fields.length, i = 0; i < a; i ++)
        {
            for(var b = fields[i].length, j = 0; j < b; j ++)
            {
                addEvent(fields[i][j], 'change', function(e, target)
                {
                    instantValidation(target);
                });
            }
        }


    })();
    </script>

</body>
</html>

In particular, the following code is not toally clear to me:

    function addEvent(node, type, callback)
    {
        if(node.addEventListener)
        {
            node.addEventListener(type, function(e)
            {
                callback(e, e.target);

            }, false);
        }
        else if(node.attachEvent)
        {
            node.attachEvent('on' + type, function(e)
            {
                callback(e, e.srcElement);
            });
        }
    }

Any help (even a very brief explanation) would be highly appreciated !

like image 459
user3177810 Avatar asked Oct 01 '22 22:10

user3177810


2 Answers

#1 That's an event handler abstraction layer.

That one code section acts as an event handler, but works across various different browsers.

  • Most browsers use the addEventListener way of adding an event handler.

  • Some Internet Explorer versions use attachEvent: http://msdn.microsoft.com/en-us/library/ie/ms536343(v=vs.85).aspx

The function allows both ways to be used.

It has you pass in...

  • ... the element you want to add an event to (node)
  • ... what type of event you want to handle (type)
  • ... what code you want executed by an event (callback)

Browser events: http://eloquentjavascript.net/chapter13.html

Abstraction layers: http://en.wikipedia.org/wiki/Abstraction_layer

Browser events are things like a page fulling loading (onload), something being clicked (onclick), an input being changed (onchange), a cursor going over an element (onmouseover), etc...

http://www.w3schools.com/js/js_htmldom_events.asp

#2 How to go about invoking validation onSubmit...

//now bind a change event to each applicable for field

The code below that goes through each input and textarea element and adds validation to each one with the onchange event. But what you want to do is validate onsubmit, which requires something like this, below the other addEvent call:

addEvent("myform","onsubmit", function(){
    //de Go field by field and validate.
    //de If all the fields pass, return true.
    //de If one or more fields fail, return false.
})

If you want, you can even remove the onChange events. That is your choice. The main thing here is that you need to make sure to only validate the fields inside the form itself, which you can look at this answer for more information about: Best Practice: Access form elements by HTML id or name attribute? ... loop through all the elements, and validate each one within the addEvent I mentioned above which must return true or false to either allow the form to be submitted, or stop the submission and show that there were validation errors.

Please remember! As a personal bit of advice... On the server-side you still want to do validation, even if you have client-side validation. Browsers are easy to manipulate, so you might still have bad data sent to the server. Always, always do server-side validation regardless of client-side.

like image 150
digitalextremist Avatar answered Oct 13 '22 08:10

digitalextremist


It just looks like a cross-browser function that attaches a handler (instantValidation) to the "change" or "onchange" events of all input and textarea controls.

I say cross-browser because of the presence of two separate event subscription methods. attachEvent is for older IE browsers (5-8) and addEventListener is generally for all modern browsers.

This addEvent function checks for the presence of said functions and uses whatever is available, giving preference to the "modern" way.

like image 28
Cᴏʀʏ Avatar answered Oct 13 '22 06:10

Cᴏʀʏ