Yii, dependent dropDownList (select)

July 9, 2017 74 Yehor Rykhnov

A detailed example of the implementation of dependent drop-down lists (select) in the Yii Framework.

A simple example of implementing a dependent dropDownList (select) in Yii

Let's start with the output of the form, add the code to the view the form and two fields of type select, the first with the choice of the country, the second with the choice of the city, which will depend on the first drop down with the choice of the country:

<?php 

$form=$this->beginWidget('CActiveForm', array(
    'id' => 'my-form',
    'enableClientValidation' => true,
    'htmlOptions' => array(
        'enctype' => 'multipart/form-data', 
        'autocomplete' => 'off',
        'role' => 'form'
    ),
    'clientOptions' => array(
        'validateOnSubmit' => true,
     )
)); 
?>

<div class="row">
    <div class="form-group">

    <?php 
    echo $form->labelEx($model, 'country_id');
    echo $form->dropDownList($model, 'country_id', CHtml::listData(Country::model()->findAll(),
        array(
            'class' => 'form-control',
            'prompt' => 'Choose the country',
            'ajax' => array(
                'type' => 'POST',
                'url' => Yii::app()->createUrl('yourController/getCitiesByCountryId'),
                'update' => '#city',
                'data' => array('country_id' => 'js:this.value'),
            )
        )
    );
    echo $form->error($model, 'country_id', array('class' => 'help-block small')); 
    ?>

    </div>
    <div class="form-group">

    <?php 
    echo $form->labelEx($model, 'city_id');
    echo $form->dropDownList(
        $model, 
        'city_id', 
        CHtml::listData(
            City::model()->findAll(
                array(
                    'condition' => 'country_id="' . $model->country_id . '"', 
                    'order' => 'position'
                )
            ), 
            'city_id', 
            'name'
        ), 
        array(
            'class' => 'form-control', 
            'id' => 'city'
        )
    );
    echo $form->error($model, 'city_id', array('class' => 'help-block small')); 
    ?>

    </div>

    <?php 
    echo CHtml::submitButton($model->isNewRecord ? 'Add' : 'Update', array('class'=>'btn btn-primary'));
$this->endWidget(); 
?>

</div>

Let's look at the presentation code. Line 21, drop-down list with a list of countries from the database. Lines 25-30, we pass the id of the selected country (29) to the post (26) in getCitiesByCountryId (27), get the answer and update the element with id "city" (28). Further everything is as usual.

Let's skip saving the model, and proceed to the conclusion of the list of cities depending on the chosen country, we add to the necessary controller the action in the output of the list of cities:

<?php

class YourController extends Controller {

    //...

    public function actionGetCitiesByCountryId() {
        $data = City::model()->findAll('country_id=:countryId',
            array(':countryId'=>(int) $_POST['country_id']));

        $data = CHtml::listData($data, 'city_id', 'name');

        echo "<option value=''>Выберите город</option>";
        foreach($data as $value => $key) {
            echo CHtml::tag('option', array('value' => $value), CHtml::encode($key), true);
        }
    }
}

An example implementation of several associated dropDownList (select) in Yii

The current example is practically the same as the previous one, but just in case it is implemented. Let's add one more field with a choice. Now the principle of work will be as follows: choose a country, depending on the chosen country, we display a list of states/regions and depending on the chosen state, output a drop-down list with a list of cities in that state.

View example:

<?php 

$form=$this->beginWidget('CActiveForm', array(
    'id' => 'my-form',
    'enableClientValidation' => true,
    'htmlOptions' => array(
        'enctype' => 'multipart/form-data', 
        'autocomplete' => 'off',
        'role' => 'form'
    ),
    'clientOptions' => array(
        'validateOnSubmit' => true,
     )
)); 
?>

<div class="row">
    <div class="form-group">

    <?php 
    echo $form->labelEx($model, 'country_id');
    echo $form->dropDownList($model, 'country_id', CHtml::listData(Country::model()->findAll(),
        array(
            'class' => 'form-control',
            'prompt' => 'Choose the country',
            'ajax' => array(
                'type' => 'POST',
                'url' => Yii::app()->createUrl('yourController/getStatesByCountryId'),
                'update' => '#state',
                'data' => array('country_id' => 'js:this.value'),
            )
        )
    );
    echo $form->error($model, 'country_id', array('class' => 'help-block small')); 
    ?>

    </div>
    <div class="form-group">

    <?php 
    echo $form->labelEx($model, 'state_id');
    echo $form->dropDownList($model, 'state_id', CHtml::listData(State::model()->findAll(),
        array(
            'class' => 'form-control',
            'prompt' => 'Select state/region',
            'ajax' => array(
                'type' => 'POST',
                'url' => Yii::app()->createUrl('yourController/getCitiesByCitiesId'),
                'update' => '#city',
                'data' => array('state_id' => 'js:this.value'),
            )
        )
    );
    echo $form->error($model, 'state_id', array('class' => 'help-block small')); 
    ?>

    </div>
    <div class="form-group">

    <?php 
    echo $form->labelEx($model, 'city_id');
    echo $form->dropDownList(
        $model, 
        'city_id', 
        CHtml::listData(
            City::model()->findAll(
                array(
                    'condition' => 'country_id="' . $model->country_id . '"', 
                    'order' => 'position'
                )
            ), 
            'city_id', 
            'name'
        ), 
        array(
            'class' => 'form-control', 
            'id' => 'city'
        )
    );
    echo $form->error($model, 'city_id', array('class' => 'help-block small')); 
    ?>

    </div>

    <?php 
    echo CHtml::submitButton($model->isNewRecord ? 'Add' : 'Update', array('class'=>'btn btn-primary'));
$this->endWidget(); 
?>

</div>

It remains to implement the actions, to display a list of states and cities, depending on the choice:

<?php

class YourController extends Controller {

    //...

    public function actionGetStatesByCountryId() {
        $data = City::model()->findAll('country_id=:countryId',
            array(':countryId'=>(int) $_POST['country_id']));

        $data = CHtml::listData($data, 'state_id', 'name');

        echo "<option value=''>Select a state/region</option>";
        foreach($data as $value => $key) {
            echo CHtml::tag('option', array('value' => $value), CHtml::encode($key), true);
        }
    }

    public function actionGetCitiesByCountryId() {
        $data = City::model()->findAll('state_id=:stateId',
            array(':stateId'=>(int) $_POST['state_id']));

        $data = CHtml::listData($data, 'city_id', 'name');

        echo "<option value=''>Select a city</option>";
        foreach($data as $value => $key) {
            echo CHtml::tag('option', array('value' => $value), CHtml::encode($key), true);
        }
    }
}

With these two examples in hand, you can implement any number of dependent drop-down lists in Yii.