While sending forms with the help of AJAX we have to somehow process errors output. Then it is getting boring and routine, and describing it for each form is not the most pleasant thing.

We have written several quite simple functions, which often move from project to project almost without changes, save time for development and reduce routine while working with forms. Nobody loves forms :)

Layout

As a rule, errors from server come in JSON-object, where the name of each server corresponds to the name of field in the form.

<input type="email" name="email"/>

At least, it is convenient and it is a good practice. If it is not like this with you, you need to have a serious talk with backend-developers :)

response = {
    ...
    responseJSON: {
        email: ['This field is required', 'Please, enter a valid email'],
        password: ['This field is requred'],
        keep: ['Something went wrong'],
        all: ['Access denied', 'Another error']
    },
    ...
}

An error in form usually looks like this (error list goes right after the corresponding field):

<form id="sign-in-form" action="">
    <div class="fieldset">
        <input type="email" placeholder="Email" name="email"/>
        <ul class="errorlist">
            <li>This field is requred</li>
            <li>Please, enter a valid email</li>
        </ul>
    </div>
    ...
    <div class="fieldset">
        <button type="submit">SIGN IN</button>
    </div>
</form>

But there are more fields:

  • which are connected to certain libraries, that add their layout right after the field or wrap it (e.g. datepicker or select2).
  • checkbox or radio button, which is followed by an explanatory text (label).

In such a case errors output will break the layout right after the field. Then go this way:

<form id="sign-in-form" action="">
    ...
    <div class="fieldset">
        <label>
            <input name="keep" type="checkbox">
            Keep me Signed In
        </label>
        <ul class="errorlist">
            <li>This field is requred</li>
            <li>Please, enter a valid email</li>
        </ul>
    </div>
    <div class="fieldset">
        <button type="submit">SIGN IN</button>
    </div>
</form>

Also, there are errors which refer to the whole form. They can be put either above form submission button or another way. For example, with the help of notify.js, or the similar library. Let’s stop at the first variant.

<form id="sign-in-form" action="">
    ...
    <div class="fieldset">
        <ul class="errorlist">
            <li>Something went wrong</li>
            <li>Another error</li>
        </ul>
        <button type="submit">SIGN IN</button>
    </div>
</form>

Error handler and template

To make the code simple we will use jQuery. But all this can be easily repeated even without this library.

In most of the times, form submission handler looks like this:

Error handler and template. Pay attention to the comments on the code.

helpers = {
        /* 
         * TEMPLATE HANDLER.
         * Actually, template handler is not necessarily to be used, and the layout for 
         * each error can be put in setErrors handler but for rather
         * voluminous layout it will be just right and will allow to 
         * make a code more readable. Also, you can easily use Underscore.js or Handlebars.js
         * Underscore.js или Handlebars.js.
         */

        messageTemplate: function ( message ) {
            return '<li>' + message + '</li>';
        },

        /* 
         * ERRORS HANDLER
         */

        setErrors: function ( errors, form, errorClass, nonfieldErrHandler ) {
            /* errors - errors object from response.
             * form - form classname or id in DOM.
             * errorClass - Errors list classname <ul></ul>.
             * nonfieldErrHandler - if you don't want to add nonfield errors
               before submit-button, you could use your own handler for that.
               it's a function with parameters (err, form).
                    err - error text
                    form - js-object of your form
             */

            var $form = $( form ),
                // get array of errors' object own properties
                errorsKeys = !!errors ? Object.keys( errors ) : [];

            // get default errors list classname, if it wasn't defined <ul></ul>.
            errorClass = !!errorClass ? errorClass : 'errorlist';

            // remove errors lists from your form
            $form.find( 'ul.' + errorClass ).remove();

            // loop the properties list
            for ( var i = 0; i < errorsKeys.length; i++ ) {
                var key = errorsKeys[i],

                    // get errors of current property
                    err = errors[key],

                    length = err.length,

                    // get the formfield that matches to error name
                    $formfield = $form.find( '[name="' + key + '"]' ),

                    // You can redefine where to put errors with the help of
                    // data-append-to attribute:
                    // right after the field or in some of its parent
                    // elements. It is made for checkbox, radio
                    // and fields, connected to libraries, and changing
                    // layout. For example, select2.

                    // Of course, there can be a mistake, if such an element is not
                    // there, but I tried not to complicate the code by the large
                    // number of checkings.
                    formfieldParent = $formfield.attr( 'data-append-to' ),
                    template = '',
                    errorsList;

                // concatinate templated errors
                for ( var j = 0; j < length; j++ ) {
                    template += helpers.messageTemplate( err[j] );
                }

                errorsList = '<ul class="' + errorClass + '">' + template + '</ul>';

                switch ( true ) {
                    // case: if 'formfieldParent' is defined, then append
                    // an errorlist to the formfield parent element.
                    case ( !!formfieldParent ):

                        $formfield = $formfield.parents( formfieldParent );
                        $formfield.append( errorsList );

                        break;

                    // case: if formfield is not defined, then append
                    // an errorlist before submit form button
                    // or use 'nonfieldErrHandler' function.
                    case ( !$formfield.length ):

                        if ( typeof nonfieldErrHandler === 'function' ) {
                            nonfieldErrHandler( err, form );
                        } else {
                            $form.find( 'button[type="submit"]' ).before( errorsList );
                        }

                        break;

                    // default case: if formfield is defined, then append
                    // an errorlist after it.
                    default:
                        $formfield.after( errorsList );

                        break;
                }
            }
        }
    };

That is all. In practice, these two functions can vary depending on the project. A universal one can be written, but it can become very cumbersome and complex, but it is real to do it on your own.

Example

Example In the example, we simulated the errors returned from the server.

By the way, we believe, that these useful functions can be used in SPAs. This will not clutter up your controllers or viewmodels by redundant code.