- Getting Started
- Fundamentals
- Working with Forms
- Working with Databases
- Caching
- Extending Yii
- Testing
- Special Topics
Sometimes we want to collect user input in a batch mode. That is, the user can enter the information for multiple model instances and submit them all at once. We call this tabular input because the input fields are often presented in an HTML table.
To work with tabular input, we first need to create or populate an array
of model instances, depending on whether we are inserting or updating the
data. We then retrieve the user input data from the $_POST variable and
assign it to each model. A slight difference from single model input is
that we retrieve the input data using $_POST['ModelClass'][$i] instead of
$_POST['ModelClass'].
public function actionBatchUpdate() { // retrieve items to be updated in a batch mode // assuming each item is of model class 'Item' $items=$this->getItemsToUpdate(); if(isset($_POST['Item'])) { $valid=true; foreach($items as $i=>$item) { if(isset($_POST['Item'][$i])) $item->attributes=$_POST['Item'][$i]; $valid=$valid && $item->validate(); } if($valid) // all items are valid // ...do something here } // displays the view to collect tabular input $this->render('batchUpdate',array('items'=>$items)); }
Having the action ready, we need to work on the batchUpdate view to
display the input fields in an HTML table.
<div class="form"> <?php echo CHtml::beginForm(); <table> <tr><th>Name</th><th>Price</th><th>Count</th><th>Description</th></tr> <?php foreach($items as $i=>$item): <tr> <td><?php echo CHtml::activeTextField($item,"[$i]name"); </td> <td><?php echo CHtml::activeTextField($item,"[$i]price"); </td> <td><?php echo CHtml::activeTextField($item,"[$i]count"); </td> <td><?php echo CHtml::activeTextArea($item,"[$i]description"); </td> </tr> <?php endforeach; </table> <?php echo CHtml::submitButton('Save'); <?php echo CHtml::endForm(); </div><!-- form -->
Note in the above that we use "[$i]name" instead of "name" as the
second parameter when calling CHtml::activeTextField.
If there are any validation errors, the corresponding input fields will be highlighted automatically, just like the single model input we described earlier on.
This is only a alias to code look like this:
$items = MyModel::model()->findAll();
If u don't need all models apply conditions in findAll()
I needed tabular creation for model creation too. I have a case where model A belongsTo model B. I wanted a form where you create a set of model A's where each one belonged to a different model B.
If you want to perform validation on all items, this line has to be changed:
$valid = $item->validate() && $valid;
Otherwhise it'll stop after the first invalid item as the right side of the && operator will not be evaluated anymore.
shortcut doesn't invoked when using AND operators. It is only effective when you don't have to evaluate both sides.
mikl's fix works great for me, and keeps evaluation after the first error. What do you mean by your statement?
How does this work? It keeps on raising error: Property "Item." is not defined.
=(
seth_kahn, the error might come from the fact that you're still using the framework 1.0.x (current stable). In this case : <?php echo CHtml::activeTextField($item,"[$i]name"); ?>
Must be changed to : <?php echo CHtml::activeTextField($item,"name[$i]"); ?>
Worked for me ;-)
How I can perform validation on all items (without breaking the loop after an error) ? Is it normal that ALL the 'name' items are highlighted () when a validation error occurs ?
This works great but it is not so cool because I think multiple model instances is really bad and unoptimized. I think Yii should handle this internally using only one model instance. It should be able to handle attributes like :
public function rules() {
return array(
array('name[]', 'required'),
);
}
is it true: above code to work needs that item order returned by getItemsToUpdate() is the same as item order in form (created in the previous request)
if yes, maybe better idea is that, items' ids should be used as a base for items identity?
what about insert? Unlike the update,before insert, the id does not exist, if the number of uncertainty for the items, how to solve?
What is getItemsToUpdate? Were is it defined?