阿江 2017-10-03 06:30:29 5403次浏览 0条回复 2 1 0

说明

学习Yii Framework 2易2框架的过程是漫长的也是充满乐趣的以下是我学习Yii2框架时对官网英文资料(请参见原文网址)的翻译和代码实现提供了较完整的代码供你参考不妥之处请多多指正

原文网址:

http://www.yiiframework.com/doc-2.0/guide-input-forms.html

本文主题:创建表单(Creating Forms)

1、基于AR的表单:ActiveForm 2、创建列表 3、集成Pjax 4、深入阅读

1、基于AR(ActiveRecord)的表单:ActiveForm

在Yii中使用表单的方式是通过yii\widggets\ActiveForm来完成,当一个表单是基于模型时,此方法是首选方法。另外,在yii\helpers\Html中有一些有用的方法,使用它们可以为表单添加按钮和帮助文本。 一个表单,是显示在客户端的,在多数情况下会有一个响应模型,此模型用于在服务器端验证输入信息(更多信息请查看Validating Input章节)。 Validating Input章节: http://www.yiiframework.com/doc-2.0/guide-input-validation.html 当创建基于模型的表单时,第一步是先定义模型(model),此模型可以是基于AR(Active Record)类的(代表数据库中的数据),也可以是一个继承自yii\base\Model的基本模型类(Model class),后者可以获取任意类型的输入数据,例如:一个登录表单。在下例中,我们将展示如何使用一个基本模型来创建一个登录表单: <?php class LoginForm extends \yii\base\Model{

public $username;
public $password;
public function rules(){
	return [
		//在此定义一些验证规则	
	];
}

}

在控制器中,我们将传递一个模型的实例到视图中去,在视图中将使用一个ActiveForm小部件来显示表单: <?php use yii\helpers\Html; use yii\widgets\ActiveForm; $form=ActiveForm::begin([

'id'=>'login-form',
'options'=>['class'=>'form-horizontal'],

]);?>

<?=$form->field($model,'username')?>
<?=$form->field($model,'password')->passwordInput()?>
<div class="form-group">
	<div class="col-lg-offset-1 col-lg-11" >
		<?=Html::submitButton('Login',['class'=>'btn btn-primary'])?>
	</div>
</div>

<?php ActiveForm::end()?>

<?

使用begin()和end()括起来

在上例代码中ActiveForm::begin()不会产生一个表单实例,仅仅标识此处是表单的开始。放置在ActiveForm::begin()和ActiveForm::end()中的内容将被放置到HTML的

标签中。和其他小部件一样,你可以定义传递一个数组到begin()方法用于配置此小部件,此时,附加的CSS类和表单id就可以在打开的标签中使用了,关于所有可用选项,请参考yii\widgets\ActiveForm的API文件: http://www.yiiframework.com/doc-2.0/yii-widgets-activeform.html
活动字段(ActivedField)

为了在表单中创建一个带说明标签(label)和JavaScript验证的表单元素,需要调用ActiveForm::field()方法,它将返回一个yii\widgets\ActiveField实例。当此方法的输出被直接显示时,你会看到它就是一个文本的input元素。要自定义这些输出的内容,你可以在此调用上添加更多的ActiveField链式方法:

<!-- 一个密码输入框 -->
<?= $form->field($model, 'password')->passwordInput() ?>

<!--添加一个提示(在输入框下方)和自定义的说明标签  -->
<?= $form->field($model, 'username')->textInput()->hint('Please enter your name')->label('Name') ?>

<!-- 创建一个HTML5邮箱输入框 -->
<?= $form->field($model, 'email')->input('email') ?>

<? 这将生成包含、和其他标签元素,使用的是表单字段定义的模板,输入项的名称将由模型的表单名字和属性名称最终决定,例如:上例中username属性的输入项名称是LoginForm[username],此命名规则将为 所有的属性都将使用此命名规则为登录表单创建相应的输入项,这些输入项在服务器端使用$_POST['LoginForm']获取。

小贴士:如果在表单中只有一个模型,要简化输入项的名称,你可以在重写模型的formName()方法返回一个空字符串,从而覆盖表单数组中的定义,此用法在GridView中创建简洁URL时非常有用。 D:\phpwork\advanced\frontend\models\Validator.php

        public function formName() {
            return "";
        }

定义模型属性可通过许多巧妙的方法来实现,例如,当上传多个文件或选择多值时一个选项会是一个数组值,此时,你需要定义属性名称时在其后添加[]:

//允许多个文件被上传:
echo $form->field($model, 'uploadFile[]')->fileInput(['multiple'=>'multiple']);

//允许items可以多选:
echo $form->field($model, 'items[]')->checkboxList(['a' => 'Item A', 'b' => 'Item B', 'c' => 'Item C']);

要特别注意的是命名提交按钮元素的名称,jQuery文档中有一些保留字会造成冲突: 表单和它们的子元素不能使用与表单属性相冲突的名称或id,如submit、length、method,名称冲突会造成令人困惑的错误。关于一个避免此类问题的完整规则列表,请参见DOMLint文档: http://kangax.github.io/domlint/

其他的HTML标签可以使用原生的HTML或Html-helper类,如上例中的Html::submitButton()。

小贴士:如果你在应用中使用Twitter的Bootstrap CSS,你可以使用yii\bootstrap\ActiveForm替换yii\widgets\ActiveForm。此扩展表单扩展自后者,并在创建输入项时使用Bootstrap定义的样式表。

小贴士:如果要定义带星号的必填字段,你可以使用如下的CSS:

div.required label.control-label:after{
	content:"*";
	color:red;
}
2、创建列表(Creating Lists)

有3种列表: dropdown列表 radio列表 checkbox列表

要创建一个列表,需要先准备列表项,可以手工建一个:

$item=[
	1=>'item 1',
	2=>'item 2',
];

或从数据库中获取:

$item=Category::find()
	->select(['label'])
	->indexBy(['_id'=>SORT_ASC])
	->column();

这些列表项可以被不同的列表小部件处理,表单项的值(包括当前激活项)将根据$model 属性的当前值被自动设置。

创建一个下拉列表(drop-down list)

我们可以使用活动字段的yii\widgets\ActiveField::dropDownList()方法创建一个下拉列表:

echo $form->field($model,'category')->dropdownlist([
		1=>'item 1',
		2=>'itme 2',
	],
	['propt'=>'Select Category']
);
创建一个单选列表(radio list)

我们可以使用一个活动字段的yii\widgets\ActiveField::radioList()方法来创建一个单选列表:

echo $form->field($model,'category')->radioList([
		1=>'radio 1',
		2=>'radio 2',
	]);
创建一个复选框列表(checkbox list)

我们可以使用活动字段的yii\widgets\ActiveField::checkboxList()方法来创建一个复选框列表:

echo $form->field($model,'category')->checkboxList([
	1=>'checkbox 1',	
	2=>'checkbox 2'
]);
3、集成Pjax

Pjax小部件允许你更新页面中一部分,而不是整个页面,你可以在提交后使用它只替换表单部分的内容。 你可以配置$formSelector 定义来定义表单的哪个部分来触发Pjax,如果没有设置此项,则被Pjax包起来的内容中有data-pjax属性的表单都将触发Pjax请求。 $formSelector 的文档: http://www.yiiframework.com/doc-2.0/yii-widgets-pjax.html#$formSelector-detail

use yii\widgets\Pjax;
use yii\widgets\ActiveForm;
Pjax:begin([
	// Pjax选项
]);
	$form=ActiveForm::begin([
		'options'	=>['data'=>['pjax'=>true]]
		//更多ActiveForm选项
	]);
	// ActiveForm内容
	ActiveForm::end();
Pjax::end();

小贴士:在Pjax小部件内部谨慎使用连接,因为返回的内容将在小部件内容进行渲染,如果要防止此种情况,可以在HTML中使用data-ajax="0"属性。

提交按钮和文件上传的值

众所周知,在上传文件和提交按钮值时,使用jQuery.serializeArray()会存在问题,现在都在使用HTML5的FormData类来完成。 也就是说,在Ajax或使用Pjax小部件中上传文件和获取提交按钮值都将使用浏览器支持的FormData类。

使用pjax

http://www.yiiframework.com/doc-2.0/yii-widgets-pjax.html Pjax是一个小部件,它集成了jQuery的pjax插件。 pjax只处理其begin()和end()之间包含的内容,将调用小部件中定义的body内容。默认情况下,任何链接被点击,或在body内容中的表单提交(带data-ajax属性的表单)都会触发AJAX请求。作为对AJAX的请求的响应,Pjax会发送更新的body内容到客户端,这些内容会替换原有内容。浏览器的URL也会使用pushState进行更新,整个处理请求的过程将不重载模板和相关的资源(js,css)。 你可以配置$linkSelector 定义哪个链接将触发pjax,也可以配置$formSelector 来定义哪个表示的提交会触发pjax。 你可以给容器中的链接添加data-pjax="0"属性以使其不要触发pjax。 下例将展示如何与yii\grid\GridView小部件一起使用Pjax,这样分页、排序和筛选都可以通过pjax来完成。

ues yii\widgets\Pjax;
Pjax::begin();
echo GridView::widget([...]);
Pjax::end();
Pjax实例,使用Pjax方式发布新记录,并在同一个页面中直接显示出来

http://localhost:8081/country/index-pjax //post//new 原文网址:

http://www.yiichina.com/tutorial/484
http://www.yiiframework.com/wiki/772/pjax-on-activeform-and-gridview-yii2/

/ 本例存在的问题: 表单中无法进行Ajax验证,如['name', 'unique'], /

D:\phpwork\basic\controllers\CountryController.php

源代码:
    public function actionIndexPjax() {
        $model = new Country();
        if ($model->load(Yii::$app->request->post()) && $model->save())
        {
            $model = new Country();
        }
        $searchModel = new CountrySearch();
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
        return $this->render('indexPjax', ['searchModel' => $searchModel, 'dataProvider' => $dataProvider,'model' => $model,]);
    }

D:\phpwork\basic\views\country\indexPjax.php

源代码:
<?php
use yii\helpers\Html;
use yii\grid\GridView;
use yii\widgets\Pjax;
/* @var $this yii\web\View */
/* @var $searchModel app\models\CountrySearch */
/* @var $dataProvider yii\data\ActiveDataProvider */
$this->title = Yii::t('app', 'Countries Pjax');
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="country-index">
    <h1><?= Html::encode($this->title)." Time22:".time() ?></h1>
    <?php // echo $this->render('_search', ['model' => $searchModel]); ?>
    <p>
        <?= Html::a(Yii::t('app', 'Create Country'), ['create'], ['class' => 'btn btn-success']) ?>
    </p>
<?php Pjax::begin([
    'id' => 'countries',
    'enablePushState' => true,
    'timeout' => 1000,
]); ?>
    <?= GridView::widget([
        'dataProvider' => $dataProvider,
        'filterModel' => $searchModel,
        'columns' => [
            ['class' => 'yii\grid\SerialColumn'],
            'code',
            'name',
			'continent',
            'population',
            ['class' => 'yii\grid\ActionColumn'],
        ],
    ]); ?>
<?php Pjax::end(); ?>
    <?= $this->render('formPjax', [
        'model' => $model,
    ]) ?>
</div>

<? D:\phpwork\basic\views\country\formPjax.php

源代码:
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
/* @var $this yii\web\View */
/* @var $model app\models\Countries */
/* @var $form yii\widgets\ActiveForm */
?>
<?php
$this->registerJs(
    '$("document").ready(function(){ 
        $("#new_country").on("pjax:end", function() {
            $.pjax.reload({container:"#countries"});  //Reload GridView
        });
    });'
);
?>

<div class="countries-form">

    <?php yii\widgets\Pjax::begin(['id' => 'new_country']) ?>
    <?php $form = ActiveForm::begin(['options' => ['data-pjax' => true ]]); ?>

    <?= $form->field($model, 'name')->textInput(['maxlength' => 200]) ?>
    <?= $form->field($model, 'code')->textInput(['maxlength' => 2]) ?>

    <div class="form-group">
        <?= Html::submitButton($model->isNewRecord ? Yii::t('app', 'Create') : Yii::t('app', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
    </div>

    <?php ActiveForm::end(); ?>
    <?php yii\widgets\Pjax::end() ?>
</div>
测试结果:
<?
http://localhost:8081/country/index-pjax
/*
Countries Pjax Time22:1491008923
Create Country

第1-2条,共14条数据.
#	Code	Name	Continent	Population	 
1	cc	cccccc	(未设置)	(未设置)	  
2	nn	bbbbbb
*/
Pjax实例,使用Pjax方式实现列表页同一页面中显示记录详情

//detail,本例的详情在列表的下方,可改成左列表右详情的格式,更实用一些。 原文网址:

http://www.yiiframework.com/wiki/845/a-single-page-with-a-list-and-a-detail

D:\phpwork\basic\controllers\ArticlesController.php

源代码:
    public function actionIndex()
    {
        $searchModel = new ArticlesSearhch();
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
        $article=new Articles();
        return $this->render('index', [
            'searchModel' => $searchModel,
            'dataProvider' => $dataProvider,
            'article'=>$article,
        ]);
    }
    public function actionAjaxView($id)
    {
        return $this->renderPartial('_view', [
            'model' => $this->findModel($id),
        ]);
    }

D:\phpwork\basic\views\articles\index.php

源代码:
<?php
use yii\helpers\Html;
use yii\grid\GridView;
use yii\widgets\Pjax;
/* @var $this yii\web\View */
/* @var $searchModel app\models\ArticlesSearhch */
/* @var $dataProvider yii\data\ActiveDataProvider */
$this->title = Yii::t('app', 'Articles');
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="articles-index">
    <h1><?= Html::encode($this->title) ?></h1>
    <?php // echo $this->render('_search', ['model' => $searchModel]); ?>
    <p>
        <?= Html::a(Yii::t('app', 'Create Articles'), ['create'], ['class' => 'btn btn-success']) ?>
        &nbsp;&nbsp;&nbsp;
        <?= Html::a(Yii::t('app', 'Authors'), ['authors/index'], ['class' => 'btn btn-primary']) ?>
        &nbsp;&nbsp;&nbsp;
        <?= Html::a(Yii::t('app', 'Tags'), ['tag/index'], ['class' => 'btn btn-primary']) ?>
        &nbsp;&nbsp;&nbsp;
        <?= Html::a(Yii::t('app', 'Two GridView'), ['authorsql/multiple'], ['class' => 'btn btn-primary']) ?>
        &nbsp;&nbsp;&nbsp;
        <?= Html::a(Yii::t('app', 'ArticlesSql'), ['articles/index-sql'], ['class' => 'btn btn-primary']) ?>
        &nbsp;&nbsp;&nbsp;
        <?= Html::a(Yii::t('app', 'ArticlesArray'), ['articles/index-array'], ['class' => 'btn btn-primary']) ?>
        &nbsp;&nbsp;&nbsp;
        <?= Html::a(Yii::t('app', 'ArticlesGridview'), ['articles/index-gridview'], ['class' => 'btn btn-primary']) ?>
    </p>
    <?php Pjax::begin(); ?>
        <?= GridView::widget([
            'dataProvider' => $dataProvider,
            'filterModel' => $searchModel,
            //'filterPosition' =>GridView::FILTER_POS_HEADER,//将搜索框置于表头上方
            //'filterPosition' =>GridView::FILTER_POS_BODY,//默认值,将搜索框置于表头下方
    //        'filterPosition' =>GridView::FILTER_POS_FOOTER,//将搜索框置于表尾(需要先显示表尾)
    //        'showFooter' => true,//显示表尾
            'layout' => '{pager}{summary}{items}{summary}{pager}',//定义各部分的显示位置
            'emptyText' => '没有数据!',//设置没有记录时的显示信息
            'headerRowOptions' => [
                'class' => 'text-center',
            ],
            'rowOptions' => [
                'class' => 'text-center',//记录行内容居中
                'style'=>'cursor:pointer',//鼠标样式为手形
            ],
            'columns' => [
                ['class' => 'yii\grid\SerialColumn'],
                'id',
                'authors.name',
                'lastEdited:date',
                'title',
    //            'description:ntext',
                // 'content:ntext',
                // 'format',
                ['class' => 'yii\grid\ActionColumn'],
            ],
        ]); ?>
    <?php Pjax::end(); ?>
    <div id="post-detail">
        <?php echo $this->render('_view', ['model' => $article]); ?>
    </div>
</div>
<?php
$ajax_url = yii\helpers\Url::to(['ajax-view']); //获取ajax响应地址
$csrf_param = Yii::$app->request->csrfParam;  //获取csrf参数名
$csrf_token = Yii::$app->request->csrfToken; //获取csrf参数值
$this->registerJs("
$('div.articles-index').on('click', 'tr', function() { //仅对div.articles-index下的tr触发点击事件
    var id = $(this).data('key'); //获取id
    if(id){//id存在时才触发ajax请求
        $.ajax({
            'type' : 'GET',
            'url' : '$ajax_url',
            'dataType' : 'html',
            'data' : {
                //替换为变量值:
                '$csrf_param' : '$csrf_token',//'_csrf' : 'R2xwQ2F5ZC13Dx4EBAMPfwAdJRoUNRBDMxQSMycwIlgwVBIJVB0dHQ==',
                'id' : id
            },
            'success' : function(data){ //返回的数据显示
                $('#post-detail').html(data);
            }
        });
    }
});
");
?>

D:\phpwork\basic\views\articles_view.php

源代码:
<?php
use yii\helpers\Html;
use yii\widgets\DetailView;
?>
    <h1><?= Html::encode($model->title) ?></h1>
    <?= DetailView::widget([
        'model' => $model,
        'attributes' => [
            'id',
            'authorId',
            'lastEdited',
            'title',
            'description:ntext',
            'content:ntext',
            'format',
        ],
    ]) ?>
测试结果:
http://localhost:8081/articles/index
/*
北京清明假期高速路出行量将创历史新高
ID	19
authorId	5
Last Edited Time	1490940801
Title	北京清明假期高速路出行量将创历史新高
*/
4、深入阅读

下一章节Validating Input处理提交表单数据的验证问题,包括客户端的验证和ajax方式的服务器端验证。 关于表单更复杂的用法,你可以阅读以下内容:

收集选项卡输入:使用Tab为多个模型收集数据 http://www.yiiframework.com/doc-2.0/guide-input-tabular-input.html

从多模型获取数据:在同一个表单中处理多个不同的模型 http://www.yiiframework.com/doc-2.0/guide-input-multiple-models.html

上传文件:如何使用表单上传文件 http://www.yiiframework.com/doc-2.0/guide-input-file-upload.html

//ActiveForm防止重复提交的官网写法: D:\phpwork\news\controllers\SiteController.php

源代码:
    public function actionContact()
    {
        $model = new ContactForm();
        if ($model->load(Yii::$app->request->post()) && $model->contact(Yii::$app->params['adminEmail'])) {
            Yii::$app->session->setFlash('contactFormSubmitted');
            return $this->refresh();
        }
        return $this->render('contact', [
            'model' => $model,
        ]);
    }

D:\phpwork\news\views\site\contact.php

源代码:
<?php
/* @var $this yii\web\View */
/* @var $form yii\bootstrap\ActiveForm */
/* @var $model app\models\ContactForm */
use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use yii\captcha\Captcha;
$this->title = 'Contact';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="site-contact">
    <h1><?= Html::encode($this->title) ?></h1>
    <?php if (Yii::$app->session->hasFlash('contactFormSubmitted')): ?>
        <div class="alert alert-success">
            Thank you for contacting us. We will respond to you as soon as possible.
        </div>
        <p>
            Note that if you turn on the Yii debugger, you should be able
            to view the mail message on the mail panel of the debugger.
            <?php if (Yii::$app->mailer->useFileTransport): ?>
                Because the application is in development mode, the email is not sent but saved as
                a file under <code><?= Yii::getAlias(Yii::$app->mailer->fileTransportPath) ?></code>.
                Please configure the <code>useFileTransport</code> property of the <code>mail</code>
                application component to be false to enable email sending.
            <?php endif; ?>
        </p>
    <?php else: ?>
        <p>
            If you have business inquiries or other questions, please fill out the following form to contact us.
            Thank you.
        </p>
        <div class="row">
            <div class="col-lg-5">

                <?php $form = ActiveForm::begin(['id' => 'contact-form']); ?>

                    <?= $form->field($model, 'name')->textInput(['autofocus' => true]) ?>

                    <?= $form->field($model, 'email') ?>

                    <?= $form->field($model, 'subject') ?>

                    <?= $form->field($model, 'body')->textarea(['rows' => 6]) ?>

                    <?= $form->field($model, 'verifyCode')->widget(Captcha::className(), [
                        'template' => '<div class="row"><div class="col-lg-3">{image}</div><div class="col-lg-6">{input}</div></div>',
                    ]) ?>

                    <div class="form-group">
                        <?= Html::submitButton('Submit', ['class' => 'btn btn-primary', 'name' => 'contact-button']) ?>
                    </div>
                <?php ActiveForm::end(); ?>
            </div>
        </div>
    <?php endif; ?>
</div>

(全文完)

觉得很赞
    没有找到数据。
您需要登录后才可以回复。登录 | 立即注册