AJAX forms (Advanced)
Yii provides some useful AJAX-based options to make your forms more responsive and interactive. You can set Yii forms to validate fields on change and/or on form submission. This validation is performed by an AJAX call to the server validating the input fields without refreshing the page.
In this recipe we will learn how to enable AJAX support for form validations and submissions.
Getting ready
To see this in action, we will use the simple form generated in the Creating basic forms recipe.
How to do it...
Open the file
/protected/views/user/_form.php
.To enable AJAX-based server-side validation, change the property
enableAjaxValidation
totrue
with the following code:<?php $form=$this->beginWidget('CActiveForm', array( 'id'=>'user-form', 'enableAjaxValidation'=>true, )); ?>
To process AJAX validation requests, add the following lines to the action created in
UserController.php
:... $model=new User; if(isset($_POST['ajax']) && $_POST['ajax']==='user-form') { echo CActiveForm::validate($model); Yii::app()->end(); } if(isset($_POST['User'])) ...
With this, we have enabled AJAX-based server-side validation for our form.
How it works...
When we set enableAjaxValidation
to true, Yii automatically adds some JavaScript code to our form page. This code tracks the changes in the form fields and sends a request to the server to validate the changes. We can set the separate URL for validating the form data; by default, the validation requests are submitted to the action
attribute of the form. In our case it is the same actionCreate
attribute that is used to render the form.
In actionCreate
, we have added some code to check for AJAX validation requests. If we receive an AJAX request, we simply call the CActiveForm::validate($model)
method to validate the data. This method returns the validation results in JSON form, which is then passed to the client browser.
If the respective fields are valid, they will be marked with CSS for denoting class success (green color by default); else, it gets marked with red color for class error and the error description is displayed below the respective field as well as in the error-summary section.
The problem with enableAjaxValidation
is that it sends validation requests for changes in any of the form fields, by default. This creates lot of traffic on the server.
To reduce server traffic with AJAX requests, add the following lines to the form definition:
<?php $form=$this->beginWidget('CActiveForm', array( 'id'=>'user-form', 'enableAjaxValidation'=>true, 'clientOptions'=>array( 'validateOnSubmit'=>true, 'validateOnChange'=>false, ), )); ?>
With this line, we have disabled the validation requests on field-change events and enabled AJAX-based validations on submitting the form. This avoids the individual validation requests and sends a single request before final submission of the form. If this request fails, the form submission is cancelled with the error description added to the form. After successful validation, a regular POST
request is sent to the server submitting the form.
With this additional code, you get complete AJAX-based form submission:
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'user-form',
'enableAjaxValidation'=>true,
'clientOptions'=>array(
'validateOnSubmit'=>true,
'validateOnChange'=>false,
'afterValidate'=>'js:submitForm', //JS function
),
)); ?>
Add the following HTML code to _form.php
. This will hold the result of form submission.
<span id="result"></span>
Add the following JavaScript to _form.php
under protected/views/user
:
<script type="text/javascript"> function submitForm (form, data, hasError){ //check for validation errors if (!hasError){ var url = form.attr('action'); $.post(url, form.serialize(), function(res){ $('#result').html(res); }); } // return false to avoid traditional form submit return false; } </script>
Set some additional code in the actionCreate
method of UserController
, as follows:
if(isset($_POST['ajax']) && $_POST['ajax']==='user-form') { echo CActiveForm::validate($model); Yii::app()->end(); } if(Yii::app()->request->isAjaxRequest) { //do stuff like validate or save model //and set message accordingly echo 'Registration successful!!'; Yii::app()->end(); }
What we did is set the forms afterValidate
to submit AJAX request to actionCreate()
. As we are not setting $_POST['ajax']
, we track this event with Yii::app()->request->isAjaxRequest
. If it's an AJAX request, simply save the model and return the success message. This is then displayed in the span
tag on the form page.
Notice that we have set the submitForm
function to always return false
to avoid the traditional non-AJAX form submission.
There's more...
Additionally, Yii provides three static methods.
CHTML::ajaxLink()
CHTML::ajaxButton()
CHTML::ajaxSubmitButton()
These methods automatically create the respective HTML elements and additionally add the jQuery code for AJAX-based requests/response handling.
The following lines demonstrate the use of AJAX using these helpers:
echo CHtml::ajaxLink( 'Submit', array('user/view', 'id' => $id), // Yii URL array('update' => '#result') // jQuery selector );
This will create an HTML link element with the name Submit
. On clicking this link, a request is posted to actionView
of UserController
. The first parameter provides a name or text to be used for the link. The second parameter specifies its target or href
attribute. The third parameter specifies the AJAX option update that is set to replace the contents of the HTML element #result
.
You can process the response data on the client script with following callback function:
echo CHtml::ajaxLink( 'Submit', array('user/view', 'id' => $id), array( 'dataType'=>'json', 'success' => 'js:function(data){ console.log(data); alert(data.msg); //message element in response }'), );
You can find more information on AJAX forms at the following links: