Для обработки нескольких моделей одного типа в yii2 присутствует механизм пакетной обработки, который называется "табличный ввод" (пакетный ввод).
Например, в одной форме необходимо ввести неограниченное количество наименований товара. Создадим миграцию для товаров:
php yii migrate/create create_product_table
$this->createTable('{{%product}}', [
'id' => $this->primaryKey(),
'title' => $this->string()->notNull()->comment('Название'),
'description' => $this->string()->notNull()->comment('Описание'),
'cost' => $this->double()->notNull()->comment('Стоимость'),
]);
Через gii создадим модель Product
и crud-контроллер ProductController
.
Теперь изменим функцию actionCreate
:
public function actionCreate()
{
$count = count(Yii::$app->request->post('Product', []));
$model = [new Product()];
for($i = 1; $i < $count; $i++) {
$model[] = new Product();
}
if (Model::loadMultiple($model, Yii::$app->request->post()) && Model::validateMultiple($model)) {
foreach ($model as $item) {
$item->save(false);
}
return $this->redirect('index');
}
return $this->render('create', [
'model' => $model,
]);
}
В файле @app\views\product\_form.php
также произведем замену:
<?php $form = ActiveForm::begin(); ?>
<?php foreach ($model as $index => $item) : ?>
<?= $form->field($item, "[$index]title")->textInput(['maxlength' => true]) ?>
<?= $form->field($item, "[$index]description")->textInput(['maxlength' => true]) ?>
<?= $form->field($item, "[$index]cost")->textInput() ?>
<?php endforeach; ?>
<div id="ajax_forms"></div>
<div class="form-group">
<?= Html::submitButton('Save', ['class' => 'btn btn-success']) ?>
</div>
<?php ActiveForm::end(); ?>
Теперь займемся динамичным добавлением полей, для этого в @app\views\product\_form.php
добавим кнопку и скрипт. После всех изменений:
<div class="product-form">
<?= Html::a('Добавить продукт', 'javascript:void(0)', ['class' => 'btn btn-success btn-add-product', 'data-count' => $count]) ?>
<?php $form = ActiveForm::begin(); ?>
<?php foreach ($model as $index => $item) : ?>
<?= $form->field($item, "[$index]title")->textInput(['maxlength' => true]) ?>
<?= $form->field($item, "[$index]description")->textInput(['maxlength' => true]) ?>
<?= $form->field($item, "[$index]cost")->textInput() ?>
<?php endforeach; ?>
<div id="ajax_forms"></div>
<div class="form-group">
<?= Html::submitButton('Save', ['class' => 'btn btn-success']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
<?php
$script = <<< JS
$('.btn-add-product').on('click', function() {
var ths = $(this);
var cnt = ths.attr('data-count');
$.ajax({
'dataType' : 'html',
'data': {'cnt': cnt},
'success' : function(data) {
$('#ajax_forms').append(data);
ths.attr('data-count', parseInt(cnt)+1);
},
'type' : 'post',
'url' : '/product/add'
});
})
JS;
$this->registerJs($script, yii\web\View::POS_READY);
В @app\controllers\ProductController.php
добавим новый метод:
public function actionAdd()
{
$cnt = Yii::$app->request->post('cnt');
return $this->renderAjax('_add_form', [
'cnt' => $cnt,
'model' => new Product()
]);
}
Содержимое файла @app\views\product\_add_form.php
:
<div class="form-group field-product-0-title">
<?= Html::label(
$model->getAttributeLabel('title'),
"product-$cnt-title",
['class' => 'control-label'])
?>
<?= Html::textInput(
"Product[$cnt][title]",
'',
['class' => 'form-control', 'id' => "product-$cnt-title"])
?>
<div class="help-block"></div>
<?= Html::label(
$model->getAttributeLabel('description'),
"product-$cnt-description",
['class' => 'control-label'])
?>
<?= Html::textInput(
"Product[$cnt][description]",
'',
['class' => 'form-control', 'id' => "product-$cnt-description"])
?>
<div class="help-block"></div>
<?= Html::label(
$model->getAttributeLabel('cost'),
"product-$cnt-cost",
['class' => 'control-label'])
?>
<?= Html::textInput(
"Product[$cnt][cost]",
'',
['class' => 'form-control', 'id' => "product-$cnt-cost"])
?>
<div class="help-block"></div>
</div>
После всех изменений у нас готов функционал для пакетного ввода данных.
В следующей статье рассмотрим ввод данных, когда в форме должен быть реализован ввод данных для нескольких моделей, а также оптимизируем функционал табличного ввода данных.
{{ 'Comments (%count%)' | trans {count:count} }}
{{ 'Comments are closed.' | trans }}