Also available in these languages:
DeutschEnglishEspañolFrançaisBahasa Indonesia日本語polskiPortuguêsRomâniaРусскийsvenska简体中文

Collecting Tabular Input

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 is anything validation error, the corresponding input fields will be highlighted automatically, just like the single model input we described earlier on.

$Id: form.table.txt 1622 2009-12-26 20:56:05Z qiang.xue $
If you found any typos or errors in the tutorial, please create a Yii ticket to report it. If it is a translation error, please create a Yiidoc ticket, instead. Thank you.

Total 11 comments:

#513
$this->getItemsToUpdate()
by razvanpat at 7:19pm on July 29, 2009.

What is getItemsToUpdate? Were is it defined?

#551
$this->getItemsToUpdate()
by icevan at 8:30am on August 6, 2009.

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()

#578
You can adapt this for creation too
by jonah at 8:38pm on August 13, 2009.

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.

#618
Validation stops after first invalid item
by mikl at 8:45am on August 27, 2009.

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.

#636
mikl,
by pestaa at 9:55pm on September 3, 2009.

shortcut doesn't invoked when using AND operators. It is only effective when you don't have to evaluate both sides.

#666
pestaa, what do you mean?
by alf at 9:47am on September 20, 2009.

mikl's fix works great for me, and keeps evaluation after the first error. What do you mean by your statement?

#747
<?php echo CHtml::activeTextField($item,"[$i]name"); ?>
by seth_kahn at 10:12am on October 19, 2009.

How does this work? It keeps on raising error: Property "Item." is not defined.

=(

#782
<?php echo CHtml::activeTextField($item,"[$i]name"); ?>
by jobzesage at 11:34am on November 2, 2009.

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 ;-)

#1032
Ok but....
by saegeek at 1:08am on January 22, 2010.

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 ?

#1035
oops
by saegeek at 1:13am on January 23, 2010.

oops, problem solved ;-)

#1042
nice but...
by saegeek at 1:47am on January 24, 2010.

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'), ); }

Your Comment:

You may enter comment using Markdown syntax.

Please login with your forum account.
Note: you must have at least ONE forum post with your account.