Yii: How to Customize Ajax Call To Controller Without Using Native jQuery Yii Code

This is another interesting article that will definitely help many Yii developers and its community. The situation was that I wanted to use my own jQuery code to send and receives the value returned by Yii controller. However, it seems to always return me with the whole html page text. On the client side, i wasn't using any jQuery Yii code. Instead, i wrote out the logic to fit in my theme properly. The tricky part was to sent in ajax call to Yii controller. In this article, i will try to explain how this can be done without using the native jQuery Yii code. (hopefully things won't get too confusing)

Ensure Ajax Call to Controller

First thing first. We need to enable Ajax between the view and the controller. This can be easily found on google and Yii page did demonstrate a very neat way of doing this. So let's use the example one shown on Yii CActiveform page.

On the view side, we have the following code:

<?php $form = $this->beginWidget('CActiveForm', array(
    'id'=>'user-form',
    'enableAjaxValidation'=>true,
    'focus'=>array($model,'firstName'),
)); ?>

<?php echo $form->errorSummary($model); ?>

<div class="row">
    <?php echo $form->labelEx($model,'firstName'); ?>
    <?php echo $form->textField($model,'firstName'); ?>
    <?php echo $form->error($model,'firstName'); ?>
</div>
<div class="row">
    <?php echo $form->labelEx($model,'lastName'); ?>
    <?php echo $form->textField($model,'lastName'); ?>
    <?php echo $form->error($model,'lastName'); ?>
</div>

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

On the view side, we will need to use $this->beginWidget('CActiveForm', array(.... to create our form tag in order for ajax to work properly on your view. The $form->error is needed for the native Yii jQuery library,yiiactiveform, to be included.

On the controller, we have the following code:

public function actionCreate()
{
    $model=new User;
    $this->performAjaxValidation($model);
    if(isset($_POST['User']))
    {
        $model->attributes=$_POST['User'];
        if($model->save())
            $this->redirect('index');
    }
    $this->render('create',array('model'=>$model));
}

protected function performAjaxValidation($model)
{
    if(isset($_POST['ajax']) && $_POST['ajax']==='user-form')
    {
        echo CActiveForm::validate($model);
        Yii::app()->end();
    }
}

Do take note of the protected function called performAjaxValidation. This is needed for you to validate through ajax. The below code is equally important for the controller to start validating through ajax call.

$this->performAjaxValidation($model);

This is all the controller needs to validate ajax calls.

Once you have your Yii ajax setup, you should be able to make ajax call using Yii native jQuery library which doesn't really give you the flexibility you need. In this case, we will have to make our own jQuery code to interact with Yii Controller.

Making Your Own jQuery Code To Send Request To Yii Controller

Now we will need to write our own jQuery code to sent request to Yii controller. From the above Yii view code, we will need to slightly alter some value so that the Yii native jQuery code library, yiiactiveform doesn't get populated. I also added an additional div block with the id 'error' so that our error can be placed in there.

<?php $form = $this->beginWidget('CActiveForm', array(
    'id'=>'user-form',
    'enableAjaxValidation'=>true,
    'focus'=>array($model,'firstName'),
)); ?>

<?php echo $form->errorSummary($model); ?>
<div id='error'></div>
<div class="row">
    <?php echo $form->labelEx($model,'firstName'); ?>
    <?php echo $form->textField($model,'firstName'); ?>
</div>
<div class="row">
    <?php echo $form->labelEx($model,'lastName'); ?>
    <?php echo $form->textField($model,'lastName'); ?>
</div>

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

After all the long winded talk, i shall show you how this is being done.

$(document).ready(function()
{
	$('#user-form').submit(function(event)
	{
		event.preventDefault();
		var $form = $(this);
		$.ajax({
			url: $(this).attr('action'),
			dataType: 'json',
			type: 'POST',
			data : $form.serialize()+'&ajax='+$form.attr('id'),
			success: function(data, textStatus, XMLHttpRequest)
			{
				if (data != null && typeof data == 'object'){
					$.each(data, function(key, value){
						$('#error').append(value);
					});
					
				}
			},
			error: function(XMLHttpRequest, textStatus, errorThrown)
			{

			}
		});
		return false;
	}
}

If you study jquery.yiiactiveform.js closely or saw that the controller is looking for a post key to determine an ajax call, you will notice that the reason why you are failing to get a proper json object back from the controller was because you did not append the parameter 'ajax' on to the data section, you will need to append the ajax key into it so that the controller will treat it as an ajax caller and return the appropriate json object to you instead of the return page string. And this is the reason why the below controller method is so important for this to work.

protected function performAjaxValidation($model)
{
    if(isset($_POST['ajax']) && $_POST['ajax']==='user-form')
    {
        echo CActiveForm::validate($model);
        Yii::app()->end();
    }
}

got it? hope it helps 🙂