Using AJAX (Jquery) to Validate a Zend Form

The problem with using a jquery plugin like ‘Jquery Validate’ for form validation is that it results in redundant code on the client and server. The server validation code is a “must have” to allow for the fact that users can turn off Javascript on their browsers. Also validation logic that must be protected has to essentially be implemented on the server (JS code can easily be viewed by users).

The Zendcast available here explains a very elegant method to use AJAX calls to invoke validation logic defined in Zend_Form. The following code is my adaptation of the same logic.

The example described below aims to build an extremely simple form:

image

On tabbing out (blur event), use an AJAX call to validate the form, and render results:

image

1. It all begins with the Zend_Form. \application\forms\Registration.php. The form contains a single text field with  “SetRequired(true)”. This will trigger an error if an empty field is detected. Also note that the form is assigned an id of “formid” so it can be used as a handle by jquery.

class Form_Registration extends Zend_Form
{
    //put your code here
    public function init()
    {
        $this->setAttrib(‘id’, ‘formid’);
        $this->setMethod(Zend_Form::METHOD_POST);
        $name = $this->createElement(‘text’, ‘name’);
        $name->setLabel(‘Enter Name’);
        $name->setRequired(true);
        $this->addElement($name);

        $submit = $this->createElement(‘submit’, ‘submit’);
        $this->addElement($submit);
    }

}
?>

2. The next step is build the controller that utilizes the form (IndexController in our case):

<?php
class IndexController extends Zend_Controller_Action
{

    public function indexAction()
    {
        // action body
        $this->view->form = new Form_Registration();
        if ($this->_request->isPost())
        {
            if ($this->view->form->isValid($_POST))
            {
                echo “Valid form!”;
            }
        }
    }
    public function validateformAction()
    {
        $form = new Form_Registration();
        //unset($_POST['captcha']);
        $form->isValidPartial($_POST);
        $this->_helper->json($form->getMessages());
    }
}

“indexAction” is used to display the form to the user. It simply instantiates the Registration form and passes it along to the view.

“validateformAction” is invoked by an AJAX call from our view on the “blur” event of every field. Note the use of “unset” on the form post variables, and the use of  “isValidPartial()” method.

The isValidPartial() function only invokes form validation on fields that are passed in the $_POST array. The isValid() function on the other hand, runs validations on EVERY form field irrespective of whether or not it is contained in the posted array. This could cause undesirable  side effects in some cases (ex. when there is a captcha form element on the form).

NOTE: The unset method is commented out in the code, and is for explanatory purposes only- for forms that contain a “CAPTCHA” field, the “isValid” call automatically performs the validation and generates a new captcha/session id. This will cause the captcha to get validated on the ajax call.. but when the form is submitted using the submit button, it gets validated against the newly generated captcha in session, but with an image and id that were *previously* generated. Thus causing the validation to fail EVERY TIME.

The “json()” action helper is an all-encompassing magic function to disable views and layouts, set appropriate headers, json encode return values, and echo the json response (the generated error messages in this case) to the caller.

3. The view script – index.phtml

<?php
echo $this->form;
?>
<script type=”text/javascript”>
    $(‘document’).ready(function(){
        ValidateAjax.initialize(‘formid’, ‘/zfjq/public/index/validateform’);
    });
</script>

It uses the jquery library to invoke the actual JS that performs the validation. The parameters passed in are

  1. The id of the form
  2. The endpoint used for AJAX validation – the validateform action in our case.

Separating out the JS into another file like this makes it reusable across your entire app.

4. The all important javascript object – js/ValidateAjax.js

ValidateAjax = {
    initialize: function(formid, endpoint){
        end_url = endpoint;
        form_id = ‘#’+formid;

        $(form_id+’ input’).blur(function(){
            var formElementID = $(this).attr(‘id’);
            ValidateAjax.doValidate(formElementID);
            return false;
        })
    },

    doValidate: function(id){
        var url = end_url;
        var data = $(form_id).serialize();
        $.post(url,data,function(response){
            $(‘#’+id).parent().find(‘.errors’).remove();
            if (response[id])
                $(‘#’+id).parent().append(ValidateAjax.getHTML(response[id]));
        },’json’);

    },
    getHTML: function(errArray){
        var o = ‘<ul class=”errors”>’;
        $.each(errArray,function(key,value){
            o+=’<li>’+ value+’</li>’;
        });
        o+=’</ul>’;
        return o;
    }
}

The Zend_Form infrastructure automatically generates an “id=name” element for each of the form fields. We use that as a handle to access the elements.

The ‘doValidate” function makes the AJAX call using the Jquery “$.post” method. The “serialize” method is used to create a string containing all form elements and values to pass along to the script.

The ‘getHTML’ function creates an unordered list of the errors generated by the particular form element (as defined in the Zend form)

The “success” function in “doValidate” first clears error messages (if any) and then displays the formatted error message(s).

About these ads

7 comments

  1. How would I go about to bind the validator to a jQuery function so it is executed before the form is submitted? Not using a submit button, but a link with a ID now. Is there something that the validator returns that I can check for? Right now the form submits even though there are not valid fields. Great tutorial by the way!

  2. dear sir I want to request u pls give me some information about use Ajax along with javascript and PHP because i know php and java script but i don’t know so much about ajax so pls give me some source code like registration validation or login validation then i m geting little bit so
    if u send some kind of information then i use so fast pls

  3. @Chris : in this case we need to do some modifications on the json response from the server side to include status = {true or false} ..

    on your controller put this code ..

    public function validateformAction()
    {
    $form = new Form_Registration();
    //unset($_POST['captcha']);
    $status = $form->isValidPartial($_POST);
    $this->_helper->json(array('status'=> $status , 'messages' => $form->getMessages());
    }

    Now on our Js code .. modify this :

    ValidateAjax = {
    initialize: function(formid, endpoint){
    end_url = endpoint;
    form_id = ‘#’+formid;

    $(form_id+’ input’).blur(function(){
    var formElementID = $(this).attr(‘id’);
    ValidateAjax.doValidate(formElementID);
    return false;
    })
    },

    doValidate: function(id){
    var url = end_url;
    var data = $(form_id).serialize();
    $.post(url,data,function(response){
    $(‘#’+id).parent().find(‘.errors’).remove();
    if(response.status == false )
    ValidateAjax.isValid = false ;
    if (response.messages[id])
    $(‘#’+id).parent().append(ValidateAjax.getHTML(response.messages[id]));
    },’json’);

    },
    getHTML: function(errArray){
    var o = ‘’;
    $.each(errArray,function(key,value){
    o+=’’+ value+’’;
    });
    o+=’’;
    return o;
    },
    isValid : true
    }

    and now you have to bind an submit event to the form to prevent the submit if the value of ValidateAjax.isValid == false ..


    $('form').submit(function(){
    if(ValidateAjax.isValid == false )
    return false;
    });

    that’s it .. FYI i didn’t test the code i just write it as prototype answer for your question .. :)

  4. Thanks for the tutorial!

    I modified the code, so that it checks onSubmit() every field and sends the request just if everyhing is ok.

    [CODE]
    ValidateAjax = {
    initialize: function(formid, endpoint){
    end_url = endpoint;
    form_id = ‘#’ + formid;

    $(form_id+’ input’).blur(function(){
    ValidateAjax.execValidate($(this), true);
    return false;
    });

    $(form_id).submit(function()
    {
    $(form_id+’ input’).each(function(){
    ValidateAjax.execValidate($(this), false);
    });

    if($(form_id).find(‘.errors’).size() > 0) {
    return false;
    } else {
    return true;
    }
    });

    return false;
    },
    execValidate: function(obj, async)
    {
    var formElementID = obj.attr(‘id’);
    ValidateAjax.doValidate(formElementID, async);
    },
    doValidate: function(id, async){
    if(typeof async == ‘undefined’)
    {
    async = true;
    }

    var url = end_url;
    var data = $(form_id).serialize();
    $.ajax({
    type: “POST”,
    url: url,
    data: data,
    dataType: ‘json’,
    async: async,
    success: function(response){
    $(‘#’+id).parent().find(‘.errors’).remove();
    if (response[id])
    $(‘#’+id).parent().append(ValidateAjax.getHTML(response[id]));
    }
    });
    },
    getHTML: function(errArray){
    var o = ”;
    $.each(errArray,function(key,value){
    o+=”+ value+”;
    });
    o+=”;
    return o;
    }
    }
    [/CODE]

  5. hello thx for the nice tutorial!
    I have a problem to Validate the Form after Post is submitted i dont have a object of the form an i get the error: “Fatal error: Call to a member function isValid() on a non-object in N:\PROJEKTE\xampp\htdocs\ewuc\application\controllers\UserController.php on line 28″

    if i make a dump

    if ($this->_request->isPost())
    {

    var_dump($this->view->form);

    if ($this->view->form->isValid($_POST)) // LINE 28
    {
    echo “Valid form!”;
    }
    }

    I get “NULL”

    wats wrong ???

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s