Enable In-place Editing in Yii Grid

Enable In-place Editing in Yii Grid

Today someone asked me for help to integrate Jeditable with Yii CGridView. So I thought why not write a little tutorial that can help others as well.

In this article I assume that you are comfortable working with Yii; you are able to create Yii web applications and use Gii module to create models. Also, I assume that you have used JQuery and its plugins in your applications. If you are unfamiliar with any of these terms, check out the following links to learn more.

Step 1: Table Structure

For this article, we’ll consider a very simple “user” table, with following structure.

User table structure

 In this table, “status” field shows whether a user is active (allowed to login) or not. It is not very user-friendly that admin has to move to some other page, only to make a user active or inactive. We’ll see how we can allow our admin to change user’s status on grid. Now open up your application’s Gii module in browser and create model class for this table

Step 2: Action to Get Data

First we need to display users’ records in a grid. For that purpose, we’ll have to create an “action” in our controller class. 

public function actionList()
{
	$model=new User('search');
	$model->unsetAttributes();  // clear any default values
	if(isset($_GET['User']))
		$model->attributes=$_GET['User'];

	$this->render('list',array(
		'model'=>$model,
	));
}

  Step 3: View to Display Grid

Now in our “list” view, we need to add code for displaying data in Yii’s grid.

$this->widget('zii.widgets.grid.CGridView', array(
	'id'=>'user-grid',
	'dataProvider'=>$model->search(),
	'filter'=>$model,
	'columns'=>array(
		'id',
		'firstname',
		'lastname',
		'email',
		'createtime',
		'status'		
		array(
			'class'=>'CButtonColumn',
			'template' => '{update} {delete}',
		),
	),
)); 

Step 4: Customizing the Grid

The code that we have till now is the default code that can be created by Gii module. Now in order to add ability to edit in place, we’ll start customizing the grid. We’ll add a class to “status” fields so that we can later reference it from JavaScript. So, our grid code becomes

$this->widget('zii.widgets.grid.CGridView', array(
	'id'=>'user-grid',
	'dataProvider'=>$model->search(),
	'filter'=>$model,
	'columns'=>array(
		'id',
		'firstname',
		'lastname',
		'email',
		'createtime',
		'status' => array(
				'type'=>'html',
				'value' => '$data->status?"<a class=\'editable-".$data->id."\'>Active</a>":"<a class=\'editable-".$data->id."\'>Inactive</a>"',
				'name' => 'status'
		),	
		array(
			'class'=>'CButtonColumn',
			'template' => '{update} {delete}',
		),
	),
)); 

 Step 5: Adding the required JavaScript

Now we’ll add the JavaScript code to change word “Active” or “Inactive” to a drop down list so that admin can update that value.

First you’ll need to add the code to include necessary JavaScript Files to the view.

Yii::app()->clientScript->registerScriptFile(Yii::app()->request->baseUrl.'/js/jquery.jeditable.mini.js');

Next comes the actual code that will display drop down list in Yii’s grid.

Yii::app()->clientScript->registerScript('status','

	$("a[class^=editable-]").editable("'.$this->createUrl('user/status').'", {
		submitdata : function (value,settings){
						return {"User[id]":$(this).attr("class").substr("9"),};
					},
        indicator : "Saving...",
        tooltip   : "Click to edit...",
        type : "select",
        data   : "{\'1\':\'Active\',\'0\':\'Inactive\'}",
        submit   : "OK",
        name : "User[status]"
     });

',CClientScript::POS_READY);

 

For the details of options specified with Jeditable, check out plug-in’s page 

We now have a grid having status column as hyperlinks. Clicking these links display a drop down list and an “Ok” button. It may look it works perfectly fine, but there is small issue with it. Yii grid is Ajax-based. If you apply filters, click page number etc. grid performs an Ajax request to get fresh data. When this happens, the classes of new records are no longer bind to Jeditable and edit in place does not work. To fix this we’ll enclose the above piece of code in jQuery’s “live” function which binds events to current as well as future elements. So, our final piece of JavaScript code becomes

Yii::app()->clientScript->registerScript('status','

	$("a[class^=editable-]").live("click", function () {
		$(this).editable("'.$this->createUrl('user/status').'", {
			submitdata : function (value,settings){
							return {"User[id]":$(this).attr("class").substr("9"),};						},
			indicator : "Saving...",
			tooltip   : "Click to edit...",
			type : "select",
			data   : "{\'1\':\'Active\',\'0\':\'Inactive\'}",
			submit   : "OK",
			name : "User[status]"
		 });
	});	 

',CClientScript::POS_READY);

 Step 6: Updating value in DB

The last step is to code the action for our controller class which we have specified in Jeditable’s option “submitdata”. This is the function which will save the updated value back to database. A simple example of such a function is

public function actionStatus()
{
	if(isset($_POST['User']))
	{
		$model = User::model()->findByPk($_POST['User']['id']);
		if($model===null){
			throw new CHttpException(404,'The requested page does not exist.');
		}

		$model->attributes = $_POST['User'];
		if($model->save()){
			echo $model->status?"Active":"Inactive";
		}
	}
}
That is it! We have successfully added in-place editing in our gird.
I hope this is helpful to you.