Populate Select2 from Another Select2

Posted by Mr PHP on

Update the data in a select2 widget when another select2 widget changes.

Update Select2 From Another

Requirements

requires kartik-v/yii2-widget-select2:

require kartik-v/yii2-widget-select2 "@dev"

Database and Models

CREATE TABLE `client` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
);
CREATE TABLE `client_code` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `client_id` int(11) NOT NULL,
  `code` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `client_id` (`client_id`),
  CONSTRAINT `client_code_ibfk_1` FOREIGN KEY (`client_id`) REFERENCES `client` (`id`)
);
CREATE TABLE `order` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `client_id` int(11) NOT NULL,
  `client_code_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `client_id` (`client_id`),
  KEY `client_code_id` (`client_code_id`),
  CONSTRAINT `order_ibfk_2` FOREIGN KEY (`client_code_id`) REFERENCES `client_code` (`id`),
  CONSTRAINT `order_ibfk_1` FOREIGN KEY (`client_id`) REFERENCES `client` (`id`)
);

models/Client.php

<?php
namespace app\models;
class Client extends \yii\db\ActiveRecord
{
}

models/ClientCode.php

<?php
namespace app\models;
class ClientCode extends \yii\db\ActiveRecord
{
}

models/Order.php

<?php
namespace app\models;
class Order extends \yii\db\ActiveRecord
{
    public function rules()
    {
        return [
            [['client_id', 'client_code_id'], 'required'],
        ];
    }
}

Controllers and Views

The OrderController will be used to load a form to create and update orders. Each order will have a client_id and a client_code_id.

controllers/OrderController.php

<?php
namespace app\controllers;

use app\models\Order;
use Yii;
use yii\web\Controller;
use yii\web\HttpException;

class OrderController extends Controller
{
    public function actionCreate()
    {
        $model = new Order;
        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            Yii::$app->getSession()->setFlash('success', 'Order has been created.');
            return $this->redirect(['update', 'id' => $model->id]);
        } elseif (!Yii::$app->request->isPost) {
            $model->load(Yii::$app->request->get());
        }

        return $this->render('create', ['model' => $model]);
    }

    public function actionUpdate($id)
    {
        $model = $this->findModel($id);
        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            Yii::$app->getSession()->setFlash('success', 'Order has been updated.');
            return $this->redirect(['update', 'id' => $model->id]);
        } elseif (!Yii::$app->request->isPost) {
            $model->load(Yii::$app->request->get());
        }

        return $this->render('update', ['model' => $model]);
    }

    protected function findModel($id)
    {
        if (($model = Order::findOne($id)) !== null) {
            return $model;
        }
        throw new HttpException(404, 'The requested page does not exist.');
    }
}

The ClientController will have an action that is called via ajax that will be used to populate the client_code_id field whenever the client_id field is changed.

controllers\ClientController.php

<?php
namespace app\controllers;

use app\models\ClientCode;
use Yii;
use yii\web\Controller;
use yii\web\Response;

class ClientController extends Controller
{
    public function actionPopulateClientCode($id)
    {
        Yii::$app->response->format = Response::FORMAT_JSON;
        $clientCodes = ClientCode::find()->andWhere(['client_id' => $id])->all();
        $data = [['id' => '', 'text' => '']];
        foreach ($clientCodes as $clientCode) {
            $data[] = ['id' => $clientCode->id, 'text' => $clientCode->code];
        }
        return ['data' => $data];
    }
}

The views views/order/create.php and views/order/update.php will both render a form.

<?= $this->render('_form', ['model' => $model]); ?>

The order form will display 2 select2 fields, one for client_id and another for client_code_id. When client_id is changed it triggers the javascript function populateClientCode() which will perform an ajax request to /client/populate-client-code, and place the returned data into the select2 for client_code_id.

views/order/_form.php

<?php
use app\models\Client;
use app\models\ClientCode;
use kartik\select2\Select2;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
use yii\helpers\Json;
use yii\helpers\Url;
use yii\web\View;
use yii\widgets\ActiveForm;

$select2Options = [
    'multiple' => false,
    'theme' => 'krajee',
    'placeholder' => 'Type to autocomplete',
    'language' => 'en-US',
    'width' => '100%',
];
?>
<div class="product-form">

    <?php $form = ActiveForm::begin(); ?>

    <?= $form->errorSummary($model); ?>

    <fieldset>
        <legend>Client</legend>
        
        <?= $form->field($model, 'client_id')->widget(Select2::className(), [
            'model' => $model,
            'attribute' => 'client_id',
            'data' => ArrayHelper::map(Client::find()->all(), 'id', 'name'),
            'options' => $select2Options,
            'pluginEvents' => [
                'select2:select' => 'function(e) { populateClientCode(e.params.data.id); }',
            ],
        ]); ?>

        <?= $form->field($model, 'client_code_id')->widget(Select2::className(), [
            'model' => $model,
            'attribute' => 'client_code_id',
            'data' => ArrayHelper::map(ClientCode::find()->andWhere(['client_id' => $model->id])->all(), 'id', 'code'),
            'options' => $select2Options,
        ]); ?>

        <?php ob_start(); // output buffer the javascript to register later ?>
        <script>
            function populateClientCode(client_id) {
                var url = '<?= Url::to(['client/populate-client-code', 'id' => '-id-']) ?>';
                var $select = $('#order-client_code_id');
                $select.find('option').remove().end();
                $.ajax({
                    url: url.replace('-id-', client_id),
                    success: function (data) {
                        var select2Options = <?= Json::encode($select2Options) ?>;
                        select2Options.data = data.data;
                        $select.select2(select2Options);
                        $select.val(data.selected).trigger('change');
                    }
                });
            }
        </script>
        <?php $this->registerJs(str_replace(['<script>', '</script>'], '', ob_get_clean()), View::POS_END); ?>

    </fieldset>

    <?= Html::submitButton('Save'); ?>
    <?php ActiveForm::end(); ?>

</div>

Tagged with : Yii


Comments