CActiveForm + AjaxValidation - not running - SOLVED

Hi,

I was transforming my login form into one using CActiveForm and AjaxValidation, my understanding is that whenever I press the submit key this will trigger the ajax validation instead of actually reloading the page … well at least this is what it should do otherwise there is no use of ajax. Actually I was expecting that it was being able to do run the validation while typing … but since it’s not working in either way I don’t bother worrying about it now.

So I have my login form view which is like this:




<?php 

$form = $this->beginWidget('CActiveForm', array(

  'id'=>'login-form',

  'enableAjaxValidation'=>true,  

  'stateful'=>true,

));?>

  <fieldset>

    <p>

     <?php

           echo $form->labelEx($model,'username'); 

           echo $form->textField($model,'username'); 

           echo $form->error($model,'username'); 

     ?>

    </p>         

    <div class="clear"></div>                                    

    <p>

    <?php 

           echo $form->labelEx($model,'password'); 

           echo $form->textField($model,'password'); 

           echo $form->error($model,'password');                                         

    ?>

    </p>

    <div class="clear"></div>                                           

    <p>

    <?php echo CHtml::submitButton(UserModule::t("Sign In"),array('class'=>'button')); ?>

    </p>

   </fieldset>                                    

  <?php $this->endWidget(); ?>



the code above will render in this HTML:




<form id="login-form" action="/myApp/index.php/user/login" method="post"> 

<div style="display:none"><input type="hidden" name="YII_PAGE_STATE" value="" /></div>                                <fieldset> 

 <p> 

  <label for="UserLogin_username" class="required">Username <span class="required">*</span></label>

  <input name="UserLogin[username]" id="UserLogin_username" type="text" value="" />

  <div id="UserLogin_username_em_" class="errorMessage" style="display:none"></div>                                       

 </p>         

 <div class="clear"></div>                                    

 <p> 

  <label for="UserLogin_password" class="required">Password <span class="required">*</span></label>

  <input name="UserLogin[password]" id="UserLogin_password" type="text" value="" />

  <div id="UserLogin_password_em_" class="errorMessage" style="display:none"></div>                                    

 </p> 

 <div class="clear"></div>                                           

 <p> 

  <input class="button" type="submit" name="yt0" value="Sign In" />

 </p> 

</fieldset>                                    

</form>       



in the page header I can also see that a new javascript file has been added to the resources:

<script type="text/javascript" src="/myApp/assets/9130d7b5/jquery.yiiactiveform.js"></script>

I guess this is added whenever I use the class CActiveForm.

Now my LoginController looks like this:




<?php


class LoginController extends Controller

{

	public $defaultAction = 'login';


	/**

	 * Displays the login page

	 */

	public function actionLogin()

	{

		if (Yii::app()->user->isGuest) {

  		  $model=new UserLogin;            

                  $this->performAjaxValidation($model);

            

			// collect user input data

			if(isset($_POST['UserLogin']))

			{

				$model->attributes=$_POST['UserLogin'];

				// validate user input and redirect to previous page if valid

				if($model->validate()) {

					$this->lastViset();

					$this->redirect(Yii::app()->controller->module->returnUrl);

				}

			} 

			// display the login form

			$this->render('/user/login',array('model'=>$model,));

		} else

			$this->redirect(Yii::app()->controller->module->returnUrl);

	}

	

	private function lastViset() {

		$lastVisit = User::model()->notsafe()->findByPk(Yii::app()->user->id);

		$lastVisit->lastvisit = time();

		$lastVisit->save();

	}


    protected function performAjaxValidation($model)

    {

        if(isset($_POST['ajax']) && $_POST['ajax']==='login-form')

        {

            echo CActiveForm::validate($model);

            Yii::app()->end();

        }

    }        

}



The validation rules set in the UserLogin model are as follow:




	/**

	 * Declares the validation rules.

	 * The rules state that username and password are required,

	 * and password needs to be authenticated.

	 */

	public function rules()

	{

		return array(

			// username and password are required

			array('username, password', 'required'),

                        

                        // username must be minimum 5 characters long

                        array('username', 'length','min'=>5),


			// password needs to be authenticated

			array('password', 'authenticate'),

		);

	}



So from a coding and workflow point of view, I went by the book following the guide here

However whenever I put something in the input fields, nothing happen. If I use the submit button it will reload the page displaying the correct errors, but that’s not Ajax … that’s a normal POST action. I’ve monitored the GET/POST calls via FireBug and found nothing that was initiated by any HttpObject method from JS.

Does anybody have any good explanation on how to implement effectively an Ajax Validation workflow within any form in YII?

Check your controller. If you use one generated by Gii or the command line tool, you should have a commented out line in your Action that looks like this:




		// Uncomment the following line if AJAX validation is needed

		// $this->performAjaxValidation($model);



Uncomment it or make sure you have something in your actionXXXX method that is calling the ajax validation. When things are working properly, the behavior is that when you change focus from one field to the next, the validation for the field losing focus (blurring) will be validated via ajax.

Hi, thanks for taking the time to read and reply my question.

Actually if you look at my code you will see that the actionLogin method within the controller already has that line of code.

I’m tweaking an extension which does not use Ajax to validate forms, but the old CForm instead of CActiveForm.

I really don’t understand what it is missing, if you look at the documentation the performAjaxValidation method code is like this:




protected function performAjaxValidation($model)

{

    if(isset($_POST['ajax']) && $_POST['ajax']==='user-form')

    {

        echo CActiveForm::validate($model);

        Yii::app()->end();

    }

}



however I can’t find any reference in either the view code, or the rendered HTML or transmitted data of that ajax variable which should be in the $_POST array. Perhaps that’s something created on the fly by the JQuery Ajax methods but once again, I can’t see any call to any httpobject during my typing or when changing the focus or using the submit button.

There must be something missing somewhere which I quite not understand, as all the steps of the guide have been followed.

Really appreciate any help.

Thanks

T.

Ajax validation works by loosing focus… so while you are typing no validation occurs… when you get from username to password with TAB or mouse click… username should be validated…

For the validation to work jquery.js must be included and the jquery.yiiactiveform.js you already mentioned…

Near the end of the HTML source there should be something like this:




<script type="text/javascript"> 

/*<![CDATA[*/ 

jQuery(function($) { $('#login-form').yiiactiveform({'attributes':[{'inputID':'LoginForm_username','errorID':'LoginForm_username_em_'},{'inputID':'LoginForm_password','errorID':'LoginForm_password_em_'}]}); }); 

/*]]>*/ 

</script> 



P.S. By clicking the button submit - no ajax validation is done, but the whole page is submited…

P.P.S. If you don’t get this to work… try to create a new webapp by using yiic… it creates a default login form with ajax validation…

Yep that’s the way it should work.

I can confirm this code is there.

I should have thought about this earlier, I’ve created an empty application and monitored the whole Ajax interactions using firebug. I’ve managed to understand few things which are not mentioned in the user guide, have tweaked my code and now it works perfectly.

In a nutshell for everybody’s else benefit:

that’s all, Happy Coding to all of you :)

I went too fast and didn’t examine your code… I have since compared it to working code that I have and can’t find any issues. I like mdomba’s suggestion to generate a new app from yiic and do your own comparison. Sorry I couldn’t be more helpful.

Hi there,

no worries. Basically I was basing my troubleshoot on two assumptions which resulted wrongly placed:

  1. Ajax Validation would have been triggered even if the fields were empty, this is not true even if the validation rule is correctly set (‘required’)

  2. It will display the error message even not enclosing the statement in a DIV, which is not true the JQuery function is expecting a DIV to be able to change the class into the error class set (if not it will use the default one, you can find the details in the jquery.yiiactiveform.js dynamically created by the CActiveForm class).

So after having adjusted the DIV and related CSS classes, and make sure I will actually put something in the input field, it worked with no problem :)

Cheers.

T.

This should work, but of course you have to first visit the field e.g. by clicking or tabbing. Validation should take place when leaving the field (blur event). Do you see the validation messages on submit?

/Tommy

Hi Tommy,

the validation message appears on submit indeed, but not while I’m tabbing around the fields. This is not a big deal however, but it can be confusing though.

Cheers.

T.