If you are coming over to Yii 2 from Yii 1.x, you may have already read this useful wiki for creating dependent dropdowns. You can use a similar approach in Yii 2 to do the same. But if you are looking at a prebuilt solution that helps you manage it easier, read along.
Using DepDrop Widget
This widget is part of the yii2-widgets package and specifically handles dependent dropdowns. You can refer documentation and usage demos for this widget for details. The explanation of the examples is mentioned here for reference.
Tip: You can use the widget for rendering dependent dropdown lists using
yii\helpers\Html::dropDownList
AND/ORkartik\widgets\Select2 widget
.
Usage Steps
Example
- Let's assume you have 3 dropdown fields
cat
,subcat
, andprod
. subcat
depends oncat
prod
depends on bothcat
andsubcat
- Let's assume you have these following initial preselected values for the dropdown fields
$model->cat = 2; $model->subcat = 2; $model->prod = '2.2';
View
- 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 forsubcat
andprod
as seen below - Set the
url
property to an action that will be called to render the list - Set the
initialize
property totrue
for the last child in your nested list (i.e.prod
in this case). This will enable plugin to initialize each dependent dropdown with preselected value in the right order sequentially for the nested chain.
use kartik\widgets\DepDrop; use yii\helpers\Html; // Parent echo $form->field($model, 'cat')->dropDownList($catList); // $catList is the initial list of values for `cat` // Child # 1 echo $form->field($model, 'subcat')->widget(DepDrop::classname(), [ 'data' => [2 => 'Music'], // ensure at least the preselected value is available 'pluginOptions'=>[ 'depends'=>[Html::getInputId($model, 'cat')], // the id for cat attribute 'placeholder'=>'Select...', 'url'=>Url::to(['/site/subcat']) ] ]); // Child # 2 echo $form->field($model, 'prod')->widget(DepDrop::classname(), [ 'data' => ['2.2' => 'Product Music 2'], // ensure at least the preselected value is available 'pluginOptions'=>[ 'depends'=>[ Html::getInputId($model, 'cat'), // the id for cat attribute Html::getInputId($model, 'subcat'), // the id for subcat attribute ], 'placeholder'=>'Select...', 'url'=>Url::to(['/site/prod']), 'initialize'=>true ] ]);
Controller
- 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
orprod
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 demo.