My Model
controller
You have to understand that using screen shots is not a good way for showing code. It requires additional effort to read, and eventually reduces the chance for you to get help.
This is a general advice from a moderator. You can follow it or ignore it. It’s up to you.
Contoller
public function actionUpdate($id) {
$model = $this->findModel($id);
$modelsSubcategory = $model->subcategories;
if ($model->load(Yii::$app->request->post()) && $model->save()) {
$oldIDs = ArrayHelper::map($modelsSubcategory, 'id', 'id');
//var_dump($oldIDs);
$modelsSubcategory = Model::createMultiple(Subcategory::classname(), $modelsSubcategory);
Model::loadMultiple($modelsSubcategory, Yii::$app->request->post());
$deletedIDs = array_diff($oldIDs, array_filter(ArrayHelper::map($modelsSubcategory, 'id', 'id')));
// validate all models
$valid = $model->validate();
$valid = Model::validateMultiple($modelsSubcategory) && $valid;
if ($valid) {
$transaction = \Yii::$app->db->beginTransaction();
try {
if ($flag = $model->save(false)) {
if (! empty($deletedIDs)) {
Subcategory::deleteAll(['id' => $deletedIDs]);
}
foreach ($modelsSubcategory as $modelSubcategory) {
$modelSubcategory->category_id = $model->id;
if (! ($flag = $modelSubcategory->save(false))) {
$transaction->rollBack();
break;
}
}
}
if ($flag) {
$transaction->commit();
return $this->redirect(['view', 'id' => $model->id]);
}
} catch (Exception $e) {
$transaction->rollBack();
}
}
}
else {
return $this->render('update', [
'model' => $model,
'modelsSubcategory' => (empty($modelsSubcategory)) ? [new Subcategory] : $modelsSubcategory
]);
}
}
Model
namespace backend\models;
use Yii;
use yii\helpers\ArrayHelper;
class Model extends \yii\base\Model
{
/**
* Creates and populates a set of models.
*
* @param string $modelClass
* @param array $multipleModels
* @return array
*/
public static function createMultiple($modelClass, $multipleModels = [])
{
$model = new $modelClass;
$formName = $model->formName();
$post = Yii::$app->request->post($formName);
$models = [];
if (! empty($multipleModels)) {
$keys = array_keys(ArrayHelper::map($multipleModels, 'id', 'id'));
$multipleModels = array_combine($keys, $multipleModels);
}
if ($post && is_array($post)) {
foreach ($post as $i => $item) {
if (isset($item['id']) && !empty($item['id']) && isset($multipleModels[$item['id']])) {
$models[] = $multipleModels[$item['id']];
} else {
$models[] = new $modelClass;
}
}
}
unset($model, $formName, $post);
return $models;
}
}
_form.php
<div class="category-form">
<?php $form = ActiveForm::begin(['id' => 'dynamic-form']); ?>
<?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'status')->dropDownList([ '1' => 'Active', '0' => 'Inactive'], ['prompt' => 'Select']) ?>
<?= $form->field($model, 'created_at')->hiddenInput(['value' => date('Y-m-d')])->label(false) ?>
<?= $form->field($model, 'created_by')->textInput(['maxlength' => true]) ?>
<div class="row">
<div class="panel panel-default">
<div class="panel-heading"><h4><i class="glyphicon glyphicon-envelope"></i> Sub-Category</h4></div>
<div class="panel-body">
<?php DynamicFormWidget::begin([
'widgetContainer' => 'dynamicform_wrapper', // required: only alphanumeric characters plus "_" [A-Za-z0-9_]
'widgetBody' => '.container-items', // required: css class selector
'widgetItem' => '.item', // required: css class
'limit' => 4, // the maximum times, an element can be cloned (default 999)
'min' => 1, // 0 or 1 (default 1)
'insertButton' => '.add-item', // css class
'deleteButton' => '.remove-item', // css class
'model' => $modelsSubcategory[0],
'formId' => 'dynamic-form',
'formFields' => [
'name',
],
]); ?>
<div class="container-items"><!-- widgetContainer -->
<?php foreach ($modelsSubcategory as $i => $modelsSubcategory): ?>
<div class="item panel panel-default"><!-- widgetBody -->
<div class="panel-heading">
<h3 class="panel-title pull-left">Sub-Category</h3>
<div class="pull-right">
<button type="button" class="add-item btn btn-success btn-xs"><i class="glyphicon glyphicon-plus"></i></button>
<button type="button" class="remove-item btn btn-danger btn-xs"><i class="glyphicon glyphicon-minus"></i></button>
</div>
<div class="clearfix"></div>
</div>
<div class="panel-body">
<?php
// necessary for update action.
if (! $modelsSubcategory->isNewRecord) {
echo Html::activeHiddenInput($modelsSubcategory, "[{$i}]id");
}
?>
<div class="row">
<div class="col-sm-6">
<?= $form->field($modelsSubcategory, "[{$i}]name")->textInput(['maxlength' => true]) ?>
</div>
</div><!-- .row -->
</div>
</div>
<?php endforeach; ?>
</div>
<?php DynamicFormWidget::end(); ?>
</div>
</div>
</div>
<div class="form-group">
<?= Html::submitButton('Save', ['class' => 'btn btn-success']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
update.php
use yii\helpers\Html;
/* @var $this yii\web\View */
/* @var $model backend\models\Category */
$this->title = 'Update Category: ' . $model->name;
$this->params['breadcrumbs'][] = ['label' => 'Categories', 'url' => ['index']];
$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]];
$this->params['breadcrumbs'][] = 'Update';
?>
<div class="category-update">
<h1><?= Html::encode($this->title) ?></h1>
<?= $this->render('_form', [
'model' => $model,
'modelsSubcategory' => $modelsSubcategory,
]) ?>
</div>
I can create the dynamic form but i cannot update.
Ok so you should have created relation in model category. Something like that:
...
class User {
...
public function getSubcategories()
{
return $this->hasMany(Subcategory::className(), ['category_id' => 'id']);
}
}
That’s another problem.
Could you show us the stack trace?
That is the immediate point where the error has revealed itself. It’s #0 in the stack trace, somewhere in Yii Framework core code. But the real cause of the error is in your code (#10 or #20 in the stack trace, I don’t know) … probably you are handling some variable as Model
but it is null
in reality.
This error wasn’t from first version of code, we talked via private message and adding relation helped, topic should be closed.
public function getSubcategories()
{
return $this->hasMany(Subcategory::className(), ['category_id' => 'id']);