Yii 1.1-创建带验证的多步骤表单
我基本上是在尝试使用Yii中的CActiveForm类创建一个多步骤表单。我的想法是希望使用内置功能以尽可能最简单的方式实现这一点。我的要求如下:Yii 1.1-创建带验证的多步骤表单,yii,Yii,我基本上是在尝试使用Yii中的CActiveForm类创建一个多步骤表单。我的想法是希望使用内置功能以尽可能最简单的方式实现这一点。我的要求如下: 多步骤单页表单(使用jQuery显示/隐藏的div) 每个步骤上的AJAX验证(仅验证特定于步骤的属性) 验证必须使用validateOnChange()和validateOnSubmit()方法进行 这是我迄今为止开发的半工作解决方案: 查看: <div class="form"> <?php $form =
- 多步骤单页表单(使用jQuery显示/隐藏的div)
- 每个步骤上的AJAX验证(仅验证特定于步骤的属性)
- 验证必须使用
和validateOnChange()
方法进行validateOnSubmit()
<div class="form">
<?php $form = $this->beginWidget('CActiveForm', array(
'id'=>'listing-form',
'enableClientValidation'=>false,
'enableAjaxValidation'=>true,
'clientOptions'=>array(
'validateOnChange'=>true,
'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>
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
}
}
}
public function actionCreate()
{
$model = new Listing;
// step 1 ajax validation
if(isset($_POST['step1']))
{
$attributes = array('name', 'address1', 'etc');
$this->performAjaxValidation($model, $attributes);
}
// step 2 ajax validation
if(isset($_POST['step2']))
{
$attributes = array('category', 'type', 'etc');
$this->performAjaxValidation($model, $attributes);
}
// step 3 ajax validation
if(isset($_POST['step3']))
{
$attributes = array('details', 'source', 'etc');
$this->performAjaxValidation($model, $attributes);
}
// process regular POST
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();
}
}
控制器:
<div class="form">
<?php $form = $this->beginWidget('CActiveForm', array(
'id'=>'listing-form',
'enableClientValidation'=>false,
'enableAjaxValidation'=>true,
'clientOptions'=>array(
'validateOnChange'=>true,
'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>
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
}
}
}
public function actionCreate()
{
$model = new Listing;
// step 1 ajax validation
if(isset($_POST['step1']))
{
$attributes = array('name', 'address1', 'etc');
$this->performAjaxValidation($model, $attributes);
}
// step 2 ajax validation
if(isset($_POST['step2']))
{
$attributes = array('category', 'type', 'etc');
$this->performAjaxValidation($model, $attributes);
}
// step 3 ajax validation
if(isset($_POST['step3']))
{
$attributes = array('details', 'source', 'etc');
$this->performAjaxValidation($model, $attributes);
}
// process regular POST
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();
}
}
总结。基本上我有一个表单,有3个提交按钮(每个步骤一个)。在我的控制器中,我检查按下了哪个提交按钮,并对特定于该步骤的属性运行AJAX验证
我使用自定义的afterValidate()
函数在提交时显示/隐藏步骤。在步骤3中,触发默认表单提交,将所有表单属性发布到控制器
这很好,只是它不能与validateOnChange()
一起使用(因为提交按钮不会被发布)。我还想知道这是否是最好的方法,或者是否有人知道更好的方法
谢谢。我建议使用场景来打开和关闭相应的规则。根据发送到控制器的内容调整模型场景 注意:这也可能是使用CFormModel而不是CActiveRecord的好地方,这取决于表单中的内容 编辑:能否在每个div部分中添加一个隐藏字段,其中包含有关您正在执行的步骤的信息?似乎这应该可以取代提交按钮。选项1 当您没有收到按钮时,为什么不验证整个表单,为什么只需要验证特定属性?Yii将验证整个模型,发回所有错误,但只有该特定错误将由活动表单显示,因为它已经是这样工作的 选项2 您可以有3个表单(而不是现在的1个),每个步骤1个。还为每个步骤创建3个场景1 每个表单都有一个隐藏字段,该字段随表单一起发布,它实际上可以是场景名称,只需在传入时验证它即可。使用此隐藏字段验证模型以设置您所处的场景
当表单成功提交时,您可以在模型上缓存部分,并最终获得完整的模型。您可以始终进行自定义验证,并且不会破坏正常的表单验证 在您的模型中
private $step1 = false;
private $step2 = false;
private $all_ok = false;
protected function beforeValidate()
{
if(!empty($this->attr1) && $this->attr2) // if the fields you are looking for are filled, let it go to next
{
$this->step1 = true;
}
if($this->step1)
{
... some more validation
$this->step2 = true;
}
if($this->step2)
{
... if all your logic meets
$this->all_ok = true;
}
// if all fields that your looking for are filled, let parent validate them all
// if they don't go with their original rules, parent will notify
if($this->all_ok)
return parent::beforeValidate();
$this->addError($this->tableSchema->primaryKey, 'please fillout the form correctly');
return false;
}
我认为最好为验证的每个步骤创建特定的类,并使用带有规则的场景。下面是一个小例子
//protected/extensions/validators
class StepOneMyModelValidator extends CValidator
{
/**
* @inheritdoc
*/
protected function validateAttribute($object, $attribute)
{
/* @var $object YourModel */
// validation step 1 here.
if (exist_problems) {
$object->addError($attribute, 'step1 is failed');
}
...
创建其他类(步骤)以进行验证
// in your model
public function rules()
{
return array(
array('attr', 'ext.validators.StepOneMyModelValidator', 'on' => 'step1'),
...
如何在控制器中使用:
$model = new Listing();
$steps = array('step1', 'step2', /* etc... */);
foreach($_POST as $key => $val) {
if (in_array($key, $steps)) {
$model->setScenario($key);
break;
}
}
$model->validate();
echo '<pre>';
print_r($model->getErrors());
echo '</pre>';
die();
$model=newlisting();
$steps=数组('step1','step2',/*等….*/);
foreach($\发布为$key=>$val){
if(在_数组中($key,$steps)){
$model->setScenario($key);
打破
}
}
$model->validate();
回声';
打印($model->getErrors());
回声';
模具();
或者我们可以在一个验证器中验证所有步骤。表单中的数据将保存到数据库中,这就是我使用ActiveRecord的原因。我确实尝试过使用场景,但仍然没有任何不同(除了稍微简化一些控制器代码)。我仍然无法让它与validateOnChange一起工作。@GSTAR刚刚发布了另一个建议。这是因为它是一个大表单,在每个步骤中添加一个隐藏字段不会有什么区别,因为每次都会发布所有3个隐藏字段。如何在模型中使用场景?请更新你的密码