Yii2具有强大的表单验证功能,能用好表单验证,用户输入就基本掌握了,在这里我和各位聊聊Yii2的Ajax验证器
。
实际上,Yii2并没有Ajax验证器
这个概念,只是为了便于描述使用Ajax方式进行的数据验证,我在这里单独提出的一个说法而已!
所谓的Ajax验证器
,就是当enableAjaxValidation==true
时在request->isAjax
代码块中执行的验证器。
Ajax验证代码结构大概是这样:
if (Yii::$app->request->isAjax) {
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$result = \yii\bootstrap\ActiveForm::validate($model);
return $result;
}
这段代码通常存在于服务器端验证器
(即$model->validate())之前,请参考后面的源码。
Ajax验证
实际上就是由客户端触发
,使用Ajax
技术进行的服务器端验证
,验证结果以客户端页面的局部刷新
的方式展现出来,因Ajax验证良好的用户体验
而被广泛使用。
先来看看Ajax验证
是什么样的效果?
上图红框中就是
Ajax验证
的结果,在国家名称中输入了“France”,在其失去焦点(鼠标在页面空白的地方点击一下)后,输入框变为了红色
,其下方也出现了错误提示信息。需要注意的是:这个错误提示信息是由服务器端验证后发送过来的动态结果
,这与客户端验证器
是不同的。从上图右边的表格你也可以看到“France”这个国家在数据库中是
已经存在
的!上图中在国家名称中输入了“Egypt”,在其失去焦点后,输入框变为了
绿色
,即Ajax验证通过。
Ajax验证器的定义
类似的,Ajax验证器
与服务器端验证器、客户端验证器定义方式都是一样的——在rules()
中定义:
public function rules() {
return [
[['countryName','countryAbbr','continent'], 'required'],
['continent','default','value'=>'Asia'],
//Ajax验证器,对'countryName'进行唯一性(unique)检测
[['countryName'], 'unique',
//Ajax验证要使用的AR(Active Record)类
'targetClass' => '\frontend\models\Country',
//Ajax验证时,'countryName'输入项对应于'name'字段进行验证(即对Country表中的'name'字段进行查询)
'targetAttribute' => ['countryName'=>'name']
],
[['countryAbbr'], 'unique','targetClass' => '\frontend\models\Country', 'targetAttribute' => ['countryAbbr'=>'code']],
];
}
要使上例代码中countryName
验证规则成为真正的Ajax验证器
,还需要在视图文件中对enableAjaxValidation
进行设置。
在视图文件中对enableAjaxValidation
进行设置有两个可选位置:
1、在ActiveField
中对单项field进行设置
2、在ActiveForm
中对整个表单进行设置
在此推荐第1种方法
,即哪个表单项field
需要Ajax验证时,就将它的enableAjaxValidation
设置为true
,这样避免触发
不必要的Ajax请求,示例代码如下:
<?=$form->field($model,'countryName',['enableAjaxValidation'=>true])->textInput()?>
在Yii2中,ActiveForm
的enableAjaxValidation
默认值是false
,即整个表单的Ajax验证失效,但此时是可以
针对field开启单项的Ajax验证的。
if (Yii::$app->request->isAjax) {
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$result = \yii\bootstrap\ActiveForm::validate($model);
return $result;
}
最后就是在Controller
的Action
中将上面这段代码添加到$model->validate()
之前(请参考后面的源码),你的Ajax验证器就正式生效
了!
本文所涉及到的程序源码
:
文件位置:D:\phpwork\advanced\frontend\controllers\DemoController.php
<?php
namespace frontend\controllers;
use Yii;
class DemoController extends CommonController{
public function actionForm3() {
$model=new \frontend\models\Form3();
if ($model->load(Yii::$app->request->post())) {
//是Ajax请求时才执行验证
if (Yii::$app->request->isAjax) {
//使用ActiveForm的validate()方法对$model的数据进行验证
$result=\yii\bootstrap\ActiveForm::validate($model);
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;//设置返回客户端的结果使用json格式
//将验证结果返回客户端
return $result;
}
if($model->validate()){
if ($model->save()) {
return $this->render('form3a',['model'=>$model]);
}else{
return $this->error('Sorry,Data save fail!');
}
}else{
return $this->errorDisplay($model->getErrors());
}
}else{
$countries=\frontend\models\Country::find()->asArray()->all();
return $this->render('form3',['model'=>$model,'countries'=>$countries]);
}
}
}
其中errorDisplay()
方法是调用自CommonController
,请参见:
http://www.jianshu.com/p/5d2c42166702
文件位置:D:\phpwork\advanced\frontend\models\Form3.php
<?php
namespace frontend\models;
use Yii;
class Form3 extends \yii\base\Model{
public $countryName,$countryAbbr,$continent;
public function attributeLabels() {
return [
'countryName'=>'国家名称',
'countryAbbr'=>'简称',
'continent'=>'大洲',
];
}
public function rules() {
return [
[['countryName','countryAbbr','continent'], 'trim'],
[['countryName','countryAbbr','continent'], 'required'],
['continent','default','value'=>'Asia'],
//Ajax验证器,对'countryName'进行唯一性(unique)检测
[['countryName'], 'unique',
//Ajax验证要使用的AR(Active Record)类
'targetClass' => '\frontend\models\Country',
//Ajax验证时,'countryName'输入项对应于'name'字段进行验证(即对Country表中的'name'字段进行查询)
'targetAttribute' => ['countryName'=>'name']
],
[['countryAbbr'], 'unique','targetClass' => '\frontend\models\Country', 'targetAttribute' => ['countryAbbr'=>'code']],
];
}
public function save() {
return true;
}
}
文件位置:D:\phpwork\advanced\frontend\views\demo\form3.php
<?php
use yii\bootstrap\ActiveForm;
use yii\helpers\Html;
?>
<div class="panel panel-warning">
<div class="panel-heading">
<div class="panel-title">
三、Yii2的表单验证——Ajax验证的验证器
</div>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-7">
<?php
$form = ActiveForm::begin([
// 'enableClientValidation' => false,
'enableClientValidation' => true,
// 'enableAjaxValidation'=>true,//从性能考虑,避免将整个表单设置为Ajax验证
'enableAjaxValidation'=>false,//ActiveForm默认此值即为false,即整个表单的Ajax验证失效
'layout' => 'horizontal',
]);
?>
<!-- 对'countryName'进行Ajax验证,设置其enableAjaxValidation为true -->
<?=$form->field($model,'countryName',['enableAjaxValidation'=>true])->textInput()?>
<!-- 对'countryAbbr'进行Ajax验证,设置其enableAjaxValidation为true -->
<?=$form->field($model,'countryAbbr',['enableAjaxValidation'=>true])->textInput()?>
<?=$form->field($model,'continent')->textInput()?>
<div class="row">
<div class='col-md-2 col-md-offset-2'><?= Html::submitButton('提 交 ', ['class' => 'btn btn-primary form-control']) ?></div>
<div class='col-md-2 col-md-offset-2'><?= Html::resetButton('重 置 ', ['class' => 'btn btn-default form-control'])?></div>
</div>
<?php ActiveForm::end(); ?>
</div>
<div class="col-md-5">
<TABLE class="table table-bordered country">
<TR >
<TD style="width:60px;">序号</TD>
<TD>国家</TD>
<TD style="width:60px;">简称</TD>
<TD>大洲</TD>
</TR>
<?php
foreach ($countries as $k=>$item) {
echo '<TR><TD>'.($k+1).'</TD><TD>'.$item['name'].'</TD><TD>'.$item['code'].'</TD><TD>'.$item['continent'].'</TD></TR>';
}
?>
</TABLE>
</div>
</div>
</div>
</div>
文件位置:D:\phpwork\advanced\frontend\views\demo\form3a.php
<?php
use yii\widgets\DetailView;
?>
<div class="panel panel-warning">
<div class="panel-heading">
<div class="panel-title">
三、Yii2的表单验证——Ajax验证的验证器(提交数据的显示)
</div>
</div>
<div class="panel-body" style="height:500px;">
<?php
echo DetailView::widget([
'model' => $model,
'attributes' => [
'countryName',
'countryAbbr',
'continent',
],
'template' => '<tr><th class="text-right" style="width:150px;">{label}</th><td>{value}</td></tr>',
]);
?>
<button onclick="history.back()" class="btn btn-default">返 回</button>
</div>
</div>
Country
类是Yii2官网实例中的一个类,请参照官网文档自行构建。
本例涉及的数据库表country
,比官网实例中多了一个字段:continent
,手动加上亦可:
CREATE TABLE `country` (
`code` CHAR(2) NOT NULL PRIMARY KEY,
`name` CHAR(52) NOT NULL,
`continent` CHAR(52) NOT NULL,
`population` INT(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `country` VALUES ('AU','Australia',24016400,'Oceania');
INSERT INTO `country` VALUES ('BR','Brazil',205722000,'South America');
INSERT INTO `country` VALUES ('CA','Canada',35985751,'North America');
INSERT INTO `country` VALUES ('CN','China',1375210000,'Asia');
INSERT INTO `country` VALUES ('DE','Germany',81459000,'Europe');
INSERT INTO `country` VALUES ('FR','France',64513242,'Europe');
INSERT INTO `country` VALUES ('GB','United Kingdom',65097000,'Europe');
INSERT INTO `country` VALUES ('IN','India',1285400000,'Asia');
INSERT INTO `country` VALUES ('RU','Russia',146519759,'Europe');
INSERT INTO `country` VALUES ('US','United States',322976000,'North America');
欢迎深入阅读:
一处编写,三处运行的Yii2表单验证
(全文完)