2amigos / yii2-selectize-widget

Selectize From Brian Reavis Yii2 Widget
Other
73 stars 41 forks source link

SelectizeDropDownList, how to implement? #31

Closed eduardo-g-silva closed 7 years ago

eduardo-g-silva commented 7 years ago

Hi I managed to make the SelectizeTextInput with tags but I am getting kind of crazy with the SelectizeDropDownList can you guide me in what i am doing wrong

I have a form to create and edit books and one of the fields is the author of the book that comes from the author model:

This is my view

$form->field($model, 'author_id')->widget(SelectizeDropDownList::className(), [
    // calls an action that returns a JSON object with matched
    // tags
    'loadUrl' => ['author/list'],
    'items' => \yii\helpers\ArrayHelper::map(\common\models\author::find()->orderBy('name')->asArray()->all(), 'id', 'name'),
    'options' => ['class' => 'form-control'],
    'clientOptions' => [
        'valueField' => 'id',
        'persist'     => false,            
        'labelField' => 'name',
        'searchField' => ['name'],
        'autosearch' => ['on'],
        'autocemplete' => ['on'],
        'create' => true,
    ],
])

And I get the list fine but it doesn't save the author_id in the books table when i update the form

This is my list function in the author controller

public function actionList($query) {
    $models = Author::findAllByName($query);
    $items = [];

    foreach ($models as $model) {
        $items[] = ['id' => $model->id, 'name' => $model->name];
    }

    Yii::$app->response->format = \Yii::$app->response->format = 'json';

    return $items;
}

I left the book controller as it was:

public function actionUpdate($id) {
    $model = $this->findModel($id);

    if ($model->load(Yii::$app->request->post()) && $model->save()) {
        return $this->redirect(['index']);
    } else {
        return $this->render('update', [
                    'model' => $model,
                    'categories' => BookCategory::find()->active()->all(),
                    'publishers' => Publisher::find()->all(),
                    'copirights' => Copiright::find()->all(),
                    'authors' => Author::find()->all(),
        ]);
    }
}

Is it something I need to add to the Book controller?

Any help welcome,

eduardo-g-silva commented 7 years ago

not sure if this is the best way but I made it work with the following in the book controller:

public function actionUpdate($id) {
    $model = $this->findModel($id);

    if ($model->load(Yii::$app->request->post())) {
        $x = Yii::$app->request->post('Book');
        $new_author = $x['author_id'];
        if (!is_numeric($new_author)) {
            $author = new Author();
            $author->name = $new_author;
            $author->save();
            $model->author_id = $author->id;
        }
        if ($model->save()) {
            return $this->redirect(['index']);
        }
    } else {
        return $this->render('update', [
                    'model' => $model,
                    'categories' => BookCategory::find()->active()->all(),
                    'publishers' => Publisher::find()->all(),
                    'copirights' => Copiright::find()->all(),
                    'authors' => Author::find()->all(),
        ]);
    }
}
tonydspaniard commented 7 years ago

@eduardo-g-silva thats fine... but I would not do it on the controller but on the Model itself. The logic is correct. I would do it on beforeSave and also would make sure the name is not already on the relation (if any).

That issue comes when you allow the 'creation' of new items. So, you will have to check whether that id is numeric or not. But again, I would add it to the model beforeSave():

\\ on the model
public function beforeSave($insert)
{
    if(!is_numeric($this->author_id)) {
        $author = Author::find()->andFilterWhere(['name' => $this->author_id])->one();
        if(null === $author) {
            $author = new Author(); 
            $author->name = $this->author_id; 
            if($author->save()) {
                 $this->author_id = $author->id; 
            } else {
                 // add error ...
                 // you could also have author_id to be 'numeric' or 'exists' on your rules
                 // then this part is not needed
                 return false; // we are not going to proceed without author id
            }
        }
    }
    return parent::beforeSave($insert); // TODO: Change the autogenerated stub
}

Now having that on your model you can simplify your controller:

public function actionUpdate($id) {
    $model = $this->findModel($id);

    if ($model->load(Yii::$app->request->post()) {
        if ($model->save()) {
            Yii::$app->getSession()->setFlash('success', 'YES! hooray, we save it");
            return $this->redirect(['index']);
        } else {
            Yii::$app->getSession()->setFlash('danger', 'Oh man... wtf? Again? :-)'); 
        }
    } else {
        return $this->render('update', [
                    'model' => $model,
                    'categories' => BookCategory::find()->active()->all(),
                    'publishers' => Publisher::find()->all(),
                    'copirights' => Copiright::find()->all(),
                    'authors' => Author::find()->all(),
        ]);
    }
}

Hope it helps