Magento form field AJAX validation

mg_ajax_form_field_validation

In this short article I will show you a quick way of adding an AJAX-ed validation on Magento form field. If you open up the {MAGENTO_ROOT}/js/prototype/validation.js file and look into its header comments you will see that Magento’s JavaScript validation is actually done trough 3rd party JavaScript library called Really Easy Field Validation by an author named Andrew Tetlaw, with its own GIT repository available here.

As the name suggests, validation is really easy to implement and use. It is based on the basic method of attaching to the form’s onsubmit event, read out all the form elements’ classes and perform validation if required. If a field fails validation, reveal field validation advice and prevent the form from submitting. So basically in Magento you end up with form fields like

<input class="required validate-number" id="field1" name="field1" />

Here is the list of validation classes defined by default Really Easy Field Validation:

  • required (not blank)
  • validate-number (a valid number)
  • validate-digits (digits only)
  • validate-alpha (letters only)
  • validate-alphanum (only letters and numbers)
  • validate-date (a valid date value)
  • validate-email (a valid email address)
  • validate-url (a valid URL)
  • validate-date-au (a date formatted as; dd/mm/yyyy)
  • validate-currency-dollar (a valid dollar value)
  • validate-selection (first option e.g. ‘Select one…’ is not selected option)
  • validate-one-required (At least one textbox/radio element must be selected in a group)

However, if you take a detailed look at the code within {MAGENTO_ROOT}/js/prototype/validation.js file you will notice several new validation rules:

  • validate-no-html-tags
  • validate-select
  • required-entry
  • validate-number
  • validate-number-range
  • validate-digits-range
  • validate-url
  • validate-ssn
  • validate-zip-international
  • and few others…

Even with all those validations, custom requirements can sometimes ask for more. For example, imagine you are not satisfied with the validate-email validation. You are not satisfied with it because it only does the regular expression validation and not the “real deal”. Imagine you want to check if each email address actually exist in the world, not just if it is in proper format. For example, email address inchoo999888777@gmail.com would pass the built in regular expression based validation but thats not the existing email address. Webservices like http://www.towerdata.com/ can give you an option of validating email for its existence. Their API is simple, just pass the email address and check the response. Now, how do we make AJAX-ed validation rule?

Here is a code snippet that does exactly that (skin folder… /js/email/towerdata-validation.js):

Validation.add('validate-email', 'Please enter a valid email address. For example johndoe@domain.com.', function(v) {     
 
    var url = '/mycontroller/myValidateAction/email?email=' + encodeURIComponent(v);
 
    var ok = false;
 
    new Ajax.Request(url, {
        method: 'get',
        asynchronous: false,
        onSuccess: function(transport) {
            var obj = response = eval('(' + transport.responseText + ')');
            validateTrueEmailMsg = obj.status_desc;
 
            if (obj.ok === false) {
                Validation.get('validate-email').error = validateTrueEmailMsg;
                ok = false;
            } else {
                ok = true; /* return true or false */    
            }
        },
        onComplete: function() {
 
            if ($('advice-validate-email-email')) {
                $('advice-validate-email-email').remove();
            }
 
            if ($('advice-validate-email-email_address')) {
                $('advice-validate-email-email_address').remove();    
            }
 
            if ($('advice-validate-email-billing:email')) {
                $('advice-validate-email-billing:email').remove();    
            }
 
            if ($('advice-validate-email-shipping:email')) {
                $('advice-validate-email-shipping:email').remove();
            }
 
            if ($('advice-validate-email-_accountemail')) {
                $('advice-validate-email-_accountemail').remove();
            }
        }
    });
 
    return ok;
});

Example above does an synchronous AJAX call towards the custom controller action which in turn calls and handles the response from http://www.towerdata.com/ API then returns the proper response to the AJAX. The example above is not the perfect JavaScript code as I am not that into the JavaScript but it does the job. The only problem is the possible lag time of 2-4 seconds on the frontend until the AJAX executes (that is until the towerdata API gives response). Please keep in mind that although I am referencing http://www.towerdata.com API, this AJAX-ed approach can be used on anything, not just email validation.

Additionally you will notice I used “Validation.add(‘validate-email’…” to define a new rule. Since that rule already exists in the {MAGENTO_ROOT}/js/prototype/validation.js file, defining it later would simply rewrite it. Meaning you would not have to change any of the *.phtml files calling the validate-email class on input fields. If you wish to create a completely new rule, you simple give it a new name, one that hasn’t been already used.

And finally, once you have defined your rule you need to “include” it in head of the html file by doing something like this in layout xml file of your Magento theme:

<default>
    <reference name="head">
        <action method="addItem"><type>skin_js</type><name>js/email/towerdata-validation.js</name></action>
    </reference>
</default>	

Hope this helps. Cheers.


8 comments

  1. Nice article but number of Ajax call increases every time I hit submit button. For example when I hit submit for the very first time I see 2 Ajax calls in console, next click triggers 3 new calls and then 4, 5, 6 and so on.

    Unable to figure out whats wrong. Any idea?

  2. I had a need to add such validation on a project and I came to the same solution by myself. But the only problem is that synchronous AJAX isn’t ok because all sliders and the animated timer just freeze while waiting the response.
    And there’s no way in JS to wait for the response before return the result retrived form AJAX. In this way JS sucks.

  3. Spot on with this write-up, I really believe this site needs
    a great deal more attention. I’ll probably be back again to read more, thanks for the info!

  4. Hi Branko, thanks for this article. Quite helpful.

    Do you know how to modify the values that are returned from:

    $this->helper('customer/address')->getAttributeValidationClass('...')

    This function is used to set the class for all the input elements for address forms.

    I searched through the admin configuration and couldn’t find anything. I’m guessing it’s possible to set these in local.xml, but I have no idea how. I’d prefer to change some config file rather than overriding a template just to change a classname.

    Thoughts? Insights?

  5. Hi there would you mind letting me know which hosting company you’re working with? I’ve loaded your blog in 3 completely different internet browsers and
    I must say this blog loads a lot faster then most. Can you
    suggest a good hosting provider at a honest price?
    Cheers, I appreciate it!

  6. Have you ever thought about writing an ebook or guest
    authoring on other websites? I have a blog based upon on the same
    ideas you discuss and would really like
    to have you share some stories/information. I know my subscribers would enjoy your
    work. If you are even remotely interested,
    feel free to send me an email.

  7. Hi, Neat post. There’s an issue with your site in web explorer, may test this? IE still is the market leader and a good portion of people will omit your great writing because of this problem.

  8. The code above will cause browsers to lock while waiting for a response. Using synchronous calls is considered bad practice since the UX is horrible. It’s still possible to accomplish this behavior using a custom validator and an on change event handler.

    The on change event handler can trigger an AJAX (asynchronous) and it’s response callback method sets a class name depending on the result. Using an email address as an example, adding a class “email-invalid” to the input. This call back will then call the validate method again on the input. The validator method now simply checks whether the element has that class name or not.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <blockquote cite=""> <code> <del datetime=""> <em> <s> <strike> <strong>. You may use following syntax for source code: <pre><code>$current = "Inchoo";</code></pre>.