Rapidly setup GridView editable cells with EditableColumnAction

This webtip is a follow-up to setting up an editable column to manipulate records in Yii2 grid view and provides a faster and easier alternative to setting up editable cells. With release v3.0.9 of the kartik-v\yii2-grid, the module allows you to use an EditableColumnAction to rapidly set up your controller action to manage EditableColumn cells in the grid.

Before proceeding to read this webtip, please do read the setting up an editable column to manipulate records in Yii2 grid view article in detail. This webtip will explain how in Yii 2 Framework, we can setup the enhanced Krajee EditableColumn and enhanced Krajee EditableColumnAction to work with the Krajee GridView widget.

The Use Case

Let’s consider the same example of editing books in a library as seen on the Krajee grid demos page. If you watch the demo, the Book Name and Buy Amount columns are Editable. We will also consider editing of the Publish Date for the example. Let’s consider the following:

  1. We will setup the name and buy_amount attributes to be editable in the grid
  2. We will setup model validation rules for the above two attributes.
  3. We will configure the name to be edited through a HTML text input. In addition, we will also show the book_color input within the name editable form.
  4. We will configure the buy_amount to be edited through the TouchSpin widget from Krajee. We will have publish_date editable as normal text.
  5. We will setup the grid rendering controller action to also validate the editable submissions and validate posted records to save to the database.
  6. We will bypass all the other controller setups and just setup a new action via EditableColumnAction within the controller. We will refer this new action within EditableColumn::formOptions['action'] for each editable cell.

STEP 1: Setup model

Setup your model attributes and validation rules very similarly to the configuration in the earlier webtip.

/**
* Book model class
*/
class Book extends \yii\db\ActiveRecord
{
    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['name', 'buy_amount'], 'required'],
            [['name', 'buy_amount', 'publish_date'], 'safe'],
            [['buy_amount'], 'number', 'min'=>0, 'max'=>5000]
        ];
    }
}

STEP 2: Setup view (grid and editable columns)

There is a small difference in setting up your editable column in GridView versus the earlier webtip. Instead of tampering with the index action, we will add a new editable form action URL editbook to update the editable. Note the formOptions within editableOptions.

// the grid columns setup (only two column entries are shown here
// you can add more column entries you need for your use case)
$gridColumns = [
// the name column configuration
[
    'class'=>'kartik\grid\EditableColumn',
    'attribute'=>'name',
    'pageSummary'=>true,
    'editableOptions'=> function ($model, $key, $index) {
        return [
            'header'=>'Name',
            'size'=>'md',
            'formOptions'=>['action' => ['/book/editbook']], // point to the new action
            'afterInput'=>function ($form, $widget) use ($model, $index) {
                return $form->field($model, "color")->widget(\kartik\widgets\ColorInput::classname(), [
                    'showDefaultPalette'=>false,
                    'options'=>['id'=>"color-{$index}"],
                    'pluginOptions'=>[
                        'showPalette'=>true,
                        'showPaletteOnly'=>true,
                        'showSelectionPalette'=>true,
                        'showAlpha'=>false,
                        'allowEmpty'=>false,
                        'preferredFormat'=>'name',
                        'palette'=>[
                            ["white", "black", "grey", "silver", "gold", "brown"],
                            ["red", "orange", "yellow", "indigo", "maroon", "pink"],
                            ["blue", "green", "violet", "cyan", "magenta", "purple"],
                        ]
                    ],
                ]);
            }
        ];
    }
],
// the buy_amount column configuration
[
    'class'=>'kartik\grid\EditableColumn',
    'attribute'=>'buy_amount',
    'editableOptions'=>[
        'header'=>'Buy Amount',
        'formOptions'=>['action' => ['/book/editbook']], // point to the new action        
        'inputType'=>\kartik\editable\Editable::INPUT_SPIN,
        'options'=>['pluginOptions'=>['min'=>0, 'max'=>5000]]
    ],
    'hAlign'=>'right',
    'vAlign'=>'middle',
    'width'=>'100px',
    'format'=>['decimal', 2],
    'pageSummary'=>true
],
// the publish_date column configuration
[
    'class'=>'kartik\grid\EditableColumn',
    'attribute'=>'publish_date',
    'hAlign'=>'center',
    'vAlign'=>'middle',
    'filterType'=>GridView::FILTER_DATE_RANGE,
    'filterWidgetOptions'=>[
        'pluginOptions' => [
            'autoUpdateInput' => false,
        ]
    ],
    'editableOptions' => [
        'inputType' => Editable::INPUT_DATE,
        'formOptions' => ['action' => ['/book/editbook']],
        'options' => [
            'convertFormat'=>true, 
            'pluginOptions' => ['format' => 'php:Y-m-d']
        ]
    ]
],
];

// the GridView widget (you must use kartik\grid\GridView)
echo \kartik\grid\GridView::widget([
    'dataProvider'=>$dataProvider,
    'filterModel'=>$searchModel,
    'columns'=>$gridColumns
]);

STEP 3: Setup controller action

This is the part where you can see most of the change. You do not need to change the actionIndex generated by default by gii. Instead we will add a new action using EditableColumnAction to rapidly process editable column updates as shown below:

use kartik\grid\EditableColumnAction;
use yii\web\Controller;
use yii\helpers\ArrayHelper;
use app\models\Book;

class BookController extends Controller
{
   public function actions()
   {
       return ArrayHelper::merge(parent::actions(), [
           'editbook' => [                                       // identifier for your editable action
               'class' => EditableColumnAction::className(),     // action class name
               'modelClass' => Book::className(),                // the update model class
               'outputValue' => function ($model, $attribute, $key, $index) {
                    $fmt = Yii::$app->formatter;
                    $value = $model->$attribute;                 // your attribute value
                    if ($attribute === 'buy_amount') {           // selective validation by attribute
                        return $fmt->asDecimal($value, 2);       // return formatted value if desired
                    } elseif ($attribute === 'publish_date') {   // selective validation by attribute
                        return $fmt->asDate($value, 'php:Y-m-d');// return formatted value if desired
                    }
                    return '';                                   // empty is same as $value
               },
               'outputMessage' => function($model, $attribute, $key, $index) {
                     return '';                                  // any custom error after model save
               },
               // 'showModelErrors' => true,                     // show model errors after save
               // 'errorOptions' => ['header' => '']             // error summary HTML options
               // 'postOnly' => true,
               // 'ajaxOnly' => true,
               // 'findModel' => function($id, $action) {},
               // 'checkAccess' => function($action, $model) {}
           ]
       ]);
   }
}

Note the entire action can be simplified as shown below if you do not wish advanced configuration (like the outputValue setting is optional). For example:

    public function actions()
    {
        return ArrayHelper::merge(parent::actions(), [
            'editbook' => [                                       // identifier for your editable action
                'class' => EditableColumnAction::className(),     // action class name
                'modelClass' => Book::className(),                // the update model class
            ]
        ]);
    }

The action will thus automatically save the base model records edited via EditableColumn form and is a much easier way to manipulate all EditableColumn records in the GridView with one single action. For advanced cases, (e.g. where your modelClass may change), you may create multiple action identifiers within the actions array above and refer these actions within the EditableColumn::editableOptions['formOptions']['action'] configuration.

One thought on “Rapidly setup GridView editable cells with EditableColumnAction

  1. Thanks so much! I finally figured out how to make this awesomeness work with my related tables AND filtering. I appreciate you and your contributions to the project so much.

Comments are closed.