Requirements:
-
A multi step ONE PAGE form (using DIVs that show/hide with jQuery)
-
Validation on each step (validate step-specific attributes only)
I have managed to implement this as follows:
View:
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'listing-form',
'enableClientValidation'=>false,
'enableAjaxValidation'=>true,
'clientOptions'=>array(
'validateOnChange'=>false,
'validateOnSubmit'=>true,
'afterValidate'=>'js:validateListing',
),
)); ?>
<?php echo $form->errorSummary($model); ?>
<div class="step" id="step-1">
// model input fields
<?php echo CHtml::submitButton('Next Step', array('name'=>'step1')); ?>
</div>
<div class="step" id="step-2" style="display: none;">
// model input fields
<?php echo CHtml::submitButton('Next Step', array('name'=>'step2')); ?>
</div>
<div class="step" id="step-3" style="display: none;">
// model input fields
<?php echo CHtml::submitButton('Submit', array('name'=>'step3')); ?>
</div>
<?php $this->endWidget(); ?>
</div>
JS:
function validateListing(form, data, hasError)
{
if(hasError)
{
// display JS flash message
}
else
{
if($('#step-1').css('display') != 'none')
{
$('#step-1').hide();
$('#step-2').show();
}
else if($('#step-2').css('display') != 'none')
{
$('#step-2').hide();
$('#step-3').show();
}
else if($('#step-3').css('display') != 'none')
{
return true; // trigger default form submit
}
}
}
Controller:
public function actionCreate()
{
$model = new Listing;
// ajax validation
if(isset($_POST['step1']))
{
$attributes = array('name', 'address1', 'etc');
$this->performAjaxValidation($model, $attributes);
}
// ajax validation
if(isset($_POST['step2']))
{
$attributes = array('category', 'type', 'etc');
$this->performAjaxValidation($model, $attributes);
}
// ajax validation
if(isset($_POST['step3']))
{
$attributes = array('details', 'source', 'etc');
$this->performAjaxValidation($model, $attributes);
}
if(isset($_POST['Listing']))
{
$model->attributes = $_POST['Listing'];
if($model->validate()) // validate all attributes again to be sure
{
// perform save actions, redirect, etc
}
}
$this->render('create', array(
'model'=>$model,
));
}
protected function performAjaxValidation($model, $attributes=null)
{
if(isset($_POST['ajax']) && $_POST['ajax']==='listing-form')
{
echo CActiveForm::validate($model, $attributes);
Yii::app()->end();
}
}
This works well, except it won’t perform validation if you set ‘validateOnChange’ to true. Also I was wondering whether this is actually the best way to do this, or if anyone knows of a better way?
Thanks.