Валидация динамически добавлемых полей в Yii

в 9:46, , рубрики: validation, yii, yii framework, метки: ,

Все началось с новой работы, на которой пришлось отказать от Zend и перейти на Yii. При создании личного кабинета для сайта потребовались динамическое добавление полей в форме. После ковыряния в интернете пришло такое решение. Поехали:

Проблем было 2. Первое это организовать форму в несколько шагов — с этим помог справиться wizard-behavior (http://www.yiiframework.com/extension/wizard-behavior). Немного переделав, сделал на один action и одну модель. Валидация полей происходит на основе сценариев.
Добавление динамических полей сделал через ajax через render-partial вьюшки, которая содержала необходимые поля.

Форма создается во view:

$form=$this->beginWidget('CActiveForm', array(
                    'id'=>'create_order_step1',
                    'enableClientValidation'=>true,
                    'clientOptions'=>array(
                        'validateOnSubmit'=>true,
                        'validateOnType' => true,
                    ),));

В ней же выводим кнопку для добавление полей:

echo CHtml::button('добавить место', array('class' => 'place-add btn'));
<script>
$(".place-add").click(function(){
    var index = $(".new-place").size()+1;       /// считаем  кол-во уже добавленных блоков с полями. 
    $.ajax({
        success: function(html){
            $("#add_place").append(html);      // выводим во вью наши поля.
        },
        type: 'get',
        url: '/index.php/site/field',      // делаем ajax зарос к action
        data: {
            index: index
        },
        cache: false,
        dataType: 'html'
    });
});
</script>

Action:

public function actionField($index = false)
    {
        $model = new CreateOrderForm();
        $this->renderPartial('_add_place_fields', array(
            'model' => $model,
            'index' => $index,
        ));
    }

Получаем номер блока, который уже есть +1.

Динамические поля:

<table class="new-place" id="place_n<?php echo$index; ?>">                                   
        <tr>
            <td>
                <?php
                echo CHtml::activeTextField($model, "place_weight[$index]");       /// создаем поля с индексами.
                echo CHtml::error($model, "place_weight[$index]");               // вываливаем ошибки валидации
                 ?>
            </td>
        </tr>
</table>

В основном action валидацию делаем просто $model->validate(scenario) // сценарий менялся в зависимости от шага.
Если валидация не прошла тогда смотрим кол-во полей в модели и отдаем во вью. (Чтобы при ошибки валидации динамически добавленные поля не исчезли)

if(isset($model->attributes['place_weight'])){
        $count = count($model->attributes['place_weight']);
}
$this->render('view', compact('model', 'count');

Во вью для этого выводим эти поля так:

for($i =1; $i<$count; $i++){
     $this->renderPartial('_add_place_fields', array(
              'model' => $model,
              'index' => $i,
     ));
}

Ну и самое главное — Модель и валидация:

public function rules()
    {
        return array(array('place_weight', 'validatePlace', 'on'=>'step1'), );
    }
public function validatePlace($attribute,$params)       //здесь волшебная функция которая валидует массив динамически добавляемых полей.
    {
        foreach($this->place_weight as $key_w => $weight){
            if (empty($weight)) {
                $this->addError('place_weight['.$key_w.']', 'Поле должно быть заполнено');
                break;
            }
        }
}

Собственно все. Думаю начинающим в yii, вроде меня это сократит много времени.

Автор: Felingere

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js