I use CActiveForm::dropdownList()
in many, many places. To speed up development I'd like to write a widget that encapsulates all the related work. I have something that displays correctly but loses the validation functionality of CActiveForm
.
Here's how I create the dropdown directly. $activeModel
refers to the model (CActiveRecord
) used by CActiveForm
. $allItems
is a CActiveRecord
array used to populated the dropdown. This code works perfectly.
<div class="row">
<?php echo $form->labelEx($activeModel, 'keyId'); ?>:
<?php
$data = array();
foreach ($allItems as $Item) {
$data[$Item->keyId] = CHtml::encode($Item->keyName);
}
$options = array(
'prompt' => 'Select an item',
'options' => array($activeModel->keyId => array('selected' => true)),
);
echo $form->dropDownList($activeModel, 'keyId', $data, $options);
?>
<?php echo $form->error($activeModel, 'keyId'); ?>
</div>
Theoretically, here's how the widget would be included in CActiveForm
:
<div class="row">
<?php echo $form->labelEx($activeModel, 'keyId'); ?>
<?php $this->widget('path.to.CustomDropdown', array(
'form' => $form,
'items' => $allItems,
'model' => $activeModel,
'prompt' => 'Select an item',
'selected' => true,
)); ?>
<?php echo $form->error($activeModel, 'keyId'); ?>
</div>
The widget itself looks like this:
<?php
/**
* Echoes a populated <select> element
*/
class CustomDropdown extends CWidget {
public $form;
public $items = array();
public $model;
public $prompt;
public $selected = false;
/**
* @var CActiveForm $form
* @var CActiveRecord[] $items
* @var CActiveRecord $model
* @var string $prompt
* @var bool $selected (optional)
*/
public function run() {
$data = array();
foreach ($this->items as $Item) {
$data[$Item->{$Item->tableSchema->primaryKey}] = CHtml::encode($Item->getName());
}
$options = array(
'prompt' => CHtml::encode($this->prompt),
'options' => (
$this->selected ? array($this->model->{$Item->tableSchema->primaryKey} => array('selected' => true)) : array()
),
);
echo $this->form->dropDownList($this->model, $this->model->tableSchema->primaryKey, $data, $options);
}
}
?>
All of this works, but the CActiveForm
loses validation functionality in the dropdown. Specifically, the widget's $form
does not get mapped to the CActiveForm's validation array, so a submission error is never displayed to the user.
How do I fully integrate this type of widget with CActiveForm
so no functionality is lost? Thanks for the help.
Judging by your example, calling the widget causes writing more code, than in
$form->dropDownList()
call. I recommend simplify some pieces of your code and keep using widgetless solution.Why do you need this code?
You just are repeating what
CHtml::listData()
does. You can simply create drop-down like this:and selected item will be selected automatically by model attribute value.