Form validation

Hi everyone!

I have 2 questions:

  1. I have next form:

 <?php $form = ActiveForm::begin(['id' => 'travel',

            'options' => ['class'=>'travel_form'],

            'validateOnBlur' => false,

        ]); ?>

    <div class="col-lg-12">

        <table>

            <thead>

                <tr>

                    <td>Document</td>

                    <td>Number</td>

                    <td>Place of issue</td>

                    <td>Date of issue</td>

                    <td>Date of expiry</td>

                </tr>

            </thead>

                <tr>

                    <td class="f-tit lang"><span class="req">*</span> Seaman’s Book / ID

                        <?=Html::activeHiddenInput($model, "doc_id[]", ['value'=>'1']);?>

                    </td>

                    <td>

                        <?= $form->field($model,'number[]')->textInput(['placeholder'=>'Enter number'])->label(false); ?>

                    </td>

                    <td>

                        <?= $form->field($model, 'country_id[]', ['options'=>['class'=>'half']])->dropDownList(ArrayHelper::map(Countries::find()->all(), 'country_id', 'name'), ['prompt'=>'Select country'])->label(false);?>

                    </td>

                    <td>

                        <?= $form->field($model, 'issue[]')->widget(

                            DatePicker::className(), [

                                'clientOptions' => [

                                    'autoclose' => true,

                                    'format' => 'dd.mm.yyyy'

                                ]

                        ])->label(false) ?>

                    </td>

                    <td>

                        <?= $form->field($model, 'expiry[]')->widget(

                            DatePicker::className(), [

                                'clientOptions' => [

                                    'autoclose' => true,

                                    'format' => 'dd.mm.yyyy'

                                ]

                        ])->label(false) ?>

                    </td>

                </tr>

                <tr>

                    <td class="f-tit lang"><span class="req">*</span> International passport

                        <?=Html::activeHiddenInput($model, "doc_id[]", ['value'=>'2']);?>

                    </td>

                    <td>

                        <?= $form->field($model,'number[]')->textInput(['placeholder'=>'Enter number'])->label(false); ?>

                    </td>

                    <td>

                        <?= $form->field($model, 'country_id[]', ['options'=>['class'=>'half']])->dropDownList(ArrayHelper::map(Countries::find()->all(), 'country_id', 'name'), ['prompt'=>'Select country'])->label(false);?>

                    </td>

                    <td>

                        <?= $form->field($model, 'issue[]')->widget(

                            DatePicker::className(), [

                                'clientOptions' => [

                                    'autoclose' => true,

                                    'format' => 'dd.mm.yyyy'

                                ]

                        ])->label(false) ?>

                    </td>

                    <td>

                        <?= $form->field($model, 'expiry[]')->widget(

                            DatePicker::className(), [

                                'clientOptions' => [

                                    'autoclose' => true,

                                    'format' => 'dd.mm.yyyy'

                                ]

                        ])->label(false) ?>

                    </td>

                </tr>

                <tr>

                    <td class="f-tit lang">National passport

                        <?=Html::activeHiddenInput($model, "doc_id[]", ['value'=>'3']);?>

                    </td>

                    <td>

                        <?= $form->field($model,'number[]')->textInput(['placeholder'=>'Enter number'])->label(false); ?>

                    </td>

                    <td>

                        <?= $form->field($model, 'country_id[]', ['options'=>['class'=>'half']])->dropDownList(ArrayHelper::map(Countries::find()->all(), 'country_id', 'name'), ['prompt'=>'Select country'])->label(false);?>

                    </td>

                    <td>

                        <?= $form->field($model, 'issue[]')->widget(

                            DatePicker::className(), [

                                'clientOptions' => [

                                    'autoclose' => true,

                                    'format' => 'dd.mm.yyyy'

                                ]

                        ])->label(false) ?>

                    </td>

                    <td>

                        <?= $form->field($model, 'expiry[]')->widget(

                            DatePicker::className(), [

                                'clientOptions' => [

                                    'autoclose' => true,

                                    'format' => 'dd.mm.yyyy'

                                ]

                        ])->label(false) ?>

                    </td>

                </tr>

                <tr>

                    <td class="f-tit lang">US visa C1/D

                        <?=Html::activeHiddenInput($model, "doc_id[]", ['value'=>'4']);?>

                    </td>

                    <td>

                        <?= $form->field($model,'number[]')->textInput(['placeholder'=>'Enter number'])->label(false); ?>

                    </td>

                    <td>

                        <?= $form->field($model, 'country_id[]', ['options'=>['class'=>'half']])->dropDownList(ArrayHelper::map(Countries::find()->all(), 'country_id', 'name'), ['prompt'=>'Select country'])->label(false);?>

                    </td>

                    <td>

                        <?= $form->field($model, 'issue[]')->widget(

                            DatePicker::className(), [

                                'clientOptions' => [

                                    'autoclose' => true,

                                    'format' => 'dd.mm.yyyy'

                                ]

                        ])->label(false) ?>

                    </td>

                    <td>

                        <?= $form->field($model, 'expiry[]')->widget(

                            DatePicker::className(), [

                                'clientOptions' => [

                                    'autoclose' => true,

                                    'format' => 'dd.mm.yyyy'

                                ]

                        ])->label(false) ?>

                    </td>

                </tr>

                <tr>

                    <td class="f-tit lang">Schengen visa

                        <?=Html::activeHiddenInput($model, "doc_id[]", ['value'=>'5']);?>

                    </td>

                    <td>

                        <?= $form->field($model,'number[]')->textInput(['placeholder'=>'Enter number'])->label(false); ?>

                    </td>

                    <td>

                        <?= $form->field($model, 'country_id[]', ['options'=>['class'=>'half']])->dropDownList(ArrayHelper::map(Countries::find()->all(), 'country_id', 'name'), ['prompt'=>'Select country'])->label(false);?>

                    </td>

                    <td>

                        <?= $form->field($model, 'issue[]')->widget(

                            DatePicker::className(), [

                                'clientOptions' => [

                                    'autoclose' => true,

                                    'format' => 'dd.mm.yyyy'

                                ]

                        ])->label(false) ?>

                    </td>

                    <td>

                        <?= $form->field($model, 'expiry[]')->widget(

                            DatePicker::className(), [

                                'clientOptions' => [

                                    'autoclose' => true,

                                    'format' => 'dd.mm.yyyy'

                                ]

                        ])->label(false) ?>

                    </td>

                </tr>

        </table>

        <span class="add btn btn-primary" data-id="">Document</span>

    </div>

    <div class="bot">

        <div class="form-group">

            <?= Html::submitButton('Save & continue', ['class' => 'btn btn-primary', 'name' => 'signup-button', 'id' => 'f_sign']) ?>

        </div>

        <?php ActiveForm::end(); ?>

As you can see there is several inputs with same name. All of them needs to be required. I wrote standard rule:


public function rules()

    {

        return [

            [['doc_id', 'number', 'country_id', 'issue', 'expiry'], 'required'],

            [['doc_id', 'country_id'], 'integer'],

            [['issue', 'expiry'], 'safe'],

            [['number'], 'string', 'max' => 255],

        ];

    }

But when one of the fields is filled (for example first ‘country_id[]’), other passes validation.

Can anyone tell me how to separate validation of this fields?

  1. In that form I have button “.add” (‘span.add’), which adds same block of fields using ajax:

<tr>

	<td><?=Html::activeDropDownList($model,'doc_id[]', ArrayHelper::map(TravelDocs::find()->where(['!=','id','1'])->andWhere(['!=','id','2'])->andWhere(['!=','id','4'])->andWhere(['!=','id','5'])->all(), 'id', 'name'), ['prompt' => 'Select document','class'=>'form-control']);?></td>

    

    <td><?=Html::activeTextInput($model,'number[]',['placeholder'=>'Enter number','class'=>'form-control']);?></td>

    

    <td><?=Html::activeDropDownList($model,'country_id[]', ArrayHelper::map(Countries::find()->all(), 'country_id', 'name'), ['prompt' => 'Select country','class'=>'form-control']);?></td>

    


	<td>

		<?= DatePicker::widget([

		    'model' => $model,

		    'attribute' => 'issue[]',

		        'clientOptions' => [

		            'autoclose' => true,

		            'format' => 'dd.mm.yyyy'

		        ]

		]);?>

	</td>

	<td>

		<?= DatePicker::widget([

		    'model' => $model,

		    'attribute' => 'expiry[]',

		        'clientOptions' => [

		            'autoclose' => true,

		            'format' => 'dd.mm.yyyy'

		        ]

		]);?>

	</td>

</tr>

But validation rules doesn’t works on added fields.

How can I validate this part of form?

Sorry for my bad English. :unsure:

you can use ‘each’ if your ‘name is an array of arguments’, like:


['country_id', 'each', 'rule' => ['required']],

more about ‘each’ https://github.com/yiisoft/yii2/blob/master/docs/guide/tutorial-core-validators.md#yiivalidatorseachvalidatoreach-

Shame to me!I’m inattentive.

What about validation of dinamically added fields?

You should probably builid scenario when other fields are also arrays and make a custom rule for each of them:


[

    // checks if every category ID is an integer

    ['categoryIDs', 'each', 'rule' => ['integer']],

]

I can’t understand what I’m doing wrong. When using eachValidator empty form passes validation.

My rules:


public function rules()

    {

        return [

            ['lang', 'each', 'rule'=>['required']],

            ['level', 'each', 'rule'=>['required']],

        ];

    }

Form processed by Ajax:

Added ActiveForm script is empy:


<script type="text/javascript">jQuery(document).ready(function () {

jQuery('#lang').yiiActiveForm([], []);

});</script>

Yii version - 2.0.6

I’m a little confused.

Hmmm try to:

public function rules()


{


    return [


        ['lang', 'each', 'required'],


        ['level', 'each', 'required'],


    ];


}

You can awlays check if integer rule from the exampple is working with multi array argument and then if yes, ten just implement your own rule with the same syntax.

Or if it’s used to validate only your droplists you can make deafult field have value of int and the selected ones will be strings and when the droplist sill be ‘empty’ it will have dafult INT value and u will just throw your error msg ‘field can’t be empty’.

Syntax “[‘lang’, ‘each’, ‘required’],” is wrong. There is error 500 with it.

I just tested rule from example on simple form. Here’s my code:

veiw:


<?php


use yii\helpers\Html;

use yii\bootstrap\ActiveForm;


?>  


    <div class="row">

        <div class="col-lg-12">

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




                <?= $form->field($model, 'test[]')->textInput(['placeholder'=>'test'])->label('Test'); ?>

                <?= $form->field($model, 'test[]')->textInput(['placeholder'=>'test'])->label('Test'); ?>

                <?= $form->field($model, 'test[]')->textInput(['placeholder'=>'test'])->label('Test'); ?>


                <div class="form-group">

                    <?= Html::submitButton('Get started', ['class' => 'btn btn-primary', 'name' => 'signup-button']) ?>

                </div>


            <?php ActiveForm::end(); ?>

        </div>

controller:


public function actionTest()

    {

        $model = new Test();

        return $this->render('test', [

            'model' => $model,

        ]);

    }

model:


<?php

namespace frontend\models;


use yii\base\Model;

use Yii;


class Test extends Model

{

    public $test;


    public function rules()

    {

        return [

            ['test','each','rule'=>['integer']],

        ];

    }

    public function someFunc()

    {

        


        return null;

    }

}

Rule doesn’t work. :( Form successfully submitted with string data in fields.

As I understand, I have to write custom rules to validate array arguments.