New Post has been published on Krajee Web Tips
New Post has been published on http://webtips.krajee.com/managing-nested-dropdown-dependency-depdrop-widget/
Managing nested dropdown dependency with DepDrop widget
If you are coming over to Yii 2 from Yii 1.x, you may have already read this useful wiki for programming the dependency between dropdowns. You can use a similar approach in Yii 2 to do the same from scratch. But if you are looking at a ready solution and a prebuilt widget that helps you manage it easier, read along.
This widget is part of the yii2-widgets package and specifically handles dependent dropdowns. The widget is based on the dependent-dropdown jQuery plugin by Krajee. You can refer documentation and usage demos for this widget for details. The explanation of the examples is mentioned here for reference.
You can use the widget for rendering dependent dropdown lists using yii\helpers\Html::dropDownList AND/OR kartik\widgets\Select2 widget.
Let’s assume you have 3 dropdown fields cat, subcat, and prod.
prod depends on both cat and subcat
Let’s assume you have these following initial preselected values for the dropdown fields
$model->cat = 2; $model->subcat = 2; $model->prod = '2.2';
You want to initialize the fields with preselected data.
You must set the data property for the dependent fields
that must contain the preselected value as a key.
Set the depends property for subcat and prod as seen below
Set the url property to an action that will be called to render
the list
Set the initialize property to true for the last child in your nested
list (i.e. prod in this case). This will enable you to tell the plugin
to automatically fire the ajax calls on document load and generate the dropdowns
data in the right order sequentially for the nested chain.
Alternatively, you can also set the data property of each dropdown and not set
the initialize property, so that no ajax calls are fired on document load.
use kartik\widgets\DepDrop; use yii\helpers\Html; // Parent // $catList is the initial list of values for `cat` echo $form->field($model, 'cat')->dropDownList($catList); // Child # 1 echo $form->field($model, 'subcat')->widget(DepDrop::classname(), [ // ensure at least one default value is preselected 'data' => [2 => 'Music'], 'pluginOptions'=>[ // the id for cat attribute 'depends'=>[Html::getInputId($model, 'cat')], 'placeholder'=>'Select...', 'url'=>Url::to(['/site/subcat']) ] ]); // Child # 2 echo $form->field($model, 'prod')->widget(DepDrop::classname(), [ // ensure at least one default value is preselected 'data' => ['2.2' => 'Product Music 2'], 'pluginOptions'=>[ 'depends'=>[ // the id for cat attribute Html::getInputId($model, 'cat'), // the id for subcat attribute Html::getInputId($model, 'subcat'), ], 'placeholder'=>'Select...', 'url'=>Url::to(['/site/prod']), 'initialize'=>true ] ]);
The DepDrop widget uses the dependent-dropdown plugin. This plugin
triggers an ajax response on a parent dropdown change, and passes in an array variable depdrop_parents for each
dependent field.
Your controller action must read this and return a json encoded subcat or prod list based on dependencies as seen below.
Note: its important to adhere to the return format of the json encoded response as shown in the examples and in the widget documentation. This differs a bit if you are returning a list with optgroups.
// Generate list of subcat based on cat public function actionSubcat() $out = []; if (isset($_POST['depdrop_parents'])) $parents = $_POST['depdrop_parents']; if ($parents != null) $cat_id = $parents[0]; $out = self::getSubCatList($cat_id); /** * the getSubCatList function will query the database based on * the cat_id and return an array like below: * [ * ['id'=>'<sub-cat-id-1>', 'name'=>'<sub-cat-name1>'], * ['id'=>'<sub-cat_id_2>', 'name'=>'<sub-cat-name2>'] * ] */ echo Json::encode(['output'=>$out, 'selected'=>'']); return; echo Json::encode(['output'=>'', 'selected'=>'']); // Generate list of products based on cat and subcat public function actionProd() $out = []; if (isset($_POST['depdrop_parents'])) $ids = $_POST['depdrop_parents']; $cat_id = empty($ids[0]) ? null : $ids[0]; $subcat_id = empty($ids[1]) ? null : $ids[1]; if ($cat_id != null) $data = self::getProdList($cat_id, $subcat_id); /** * the getProdList function will query the database based on * the cat_id and sub_cat_id and return an array like below: * [ * 'out'=>[ * ['id'=>'<prod-id-1>', 'name'=>'<prod-name1>'], * ['id'=>'<prod_id_2>', 'name'=>'<prod-name2>'] * ], * 'selected'=>'<prod-id-1>' * ] */ echo Json::encode([ 'output'=>$data['out'], 'selected'=>$data['selected'] ]); return; echo Json::encode(['output'=>'', 'selected'=>'']);
And that’s pretty much it. You should see the dependent dropdowns working now automatically, as seen in the DepDrop widget usage and demo.