Hello,
How to create a dynamic CFormModel so that attributes can be added at runtime?
I have extended the CFormModel so that I have an array of dynamic form elements. Each element has at least name, type and a boolean value representing if it is a required form element or not.
The form is rendered so that for every element in array a corresponding element in the form is created. Later when form is posted I can iterate over the POST array and fill each elements value accordingly.
But I have problem validating the form. The rules function returns the list of these element names that has value ‘required’ set to true gets included in the list.
So am i doing it wrong? Is there a better way to create dynamic forms?
The elements class:
class Element {
public $_data = array();
public function __construct( $_data = array() ) {
$this->_data = $_data;
}
public function __get($name) {
return $this->_data[$name];
}
public function __toString() {
return $this->_data["name"];
}
}
The model:
class DynamicForm extends CFormModel {
public $elements = array();
public function rules() {
$required = array();
foreach($this->elements as $e)
if($e->required)
$required[] = $e->name;
return array(
array(implode(', ', $required), 'required'),
);
}
public function __get($name) {
foreach($this->elements as $e)
if($e->name == $name) return $this->elements[$name]->value;
return $this->$name;
}
public function attributeLabels() {
return $attributeLabels = array();
}
}
The action in controller:
public function actionDynamicForm() {
$form = new DynamicForm;
$form->elements = getFormElements();
if(isset($_POST['DynamicForm'])) {
for($i = 0; $i<sizeof($form->elements); $i++){
$e = $form->elements[$i];
$form->attributes[$e->name] = $_POST['DynamicForm'][$e->name];
$e->value = $_POST['DynamicForm'][$e->name];
}
if($form->validate()){
// TODO
} else $this->render('dynamicform', array('form'=>$form));
} else {
$this->render('dynamicform', array('form'=>$form));
}
}
The code in view that renders elements:
foreach($form->elements as $e) {
echo '<div class="simple">'."\n";
echo CHtml::activeLabelEx($form, $e->name);
switch($e->type){
case 'textfield':
echo CHtml::activeTextField($form, $e->name); break;
case 'dropdown':
echo CHtml::activeDropDownList($form, $e->name, $e->data, array('prompt'=>'Choose Item')); break;
case 'textarea':
echo CHtml::activeTextArea($form, $e->name, array('rows'=>6, 'cols'=>50)); break;
case 'radiobuttonlist':
echo '</div><div class="itemlist">';
echo CHtml::activeRadioButtonList($form, $e->name, $e->data, array('separator' => ' ')); break;
case 'checkboxlist':
echo '</div><div class="itemlist">';
echo CHtml::activeCheckBoxList($form, $e->name, $e->data, array('separator' => ' ')); break;
}
echo '</div>'."\n\n";
}