[EXTENSION] JToggleColumn

Column for CGridView which toggles the boolean ( TINYINT(1) ) value of model attribute. Tested with Yii 1.10.

www.yiiframework.com/extension/jtogglecolumn

Download: http://www.yiiframework.com/extension/jtogglecolumn/files/jtogglecolumn.zip

[size="5"]Usage[/size]

Extract downloaded zip to your components or extensions directory.

If you extracted to extensions directory add this line to import array in your /config/main.php :




<?php


'import'=>array(

    ...

    'application.extensions.jtogglecolumn.*', 

)


?>



Define a JToggleColumn in your CGrid widget:




<?php $this->widget('zii.widgets.grid.CGridView', array(

    'id'=>'user-grid',

    'dataProvider'=>$model->search(),

    'filter'=>$model,

    'columns'=>array(

            'id',

            'username',

            'password',

            'email',

            'role',

            array(

                    'class'=>'JToggleColumn',

                    'name'=>'is_active', // boolean model attribute (tinyint(1) with values 0 or 1)

                    'filter' => array('0' => 'No', '1' => 'Yes'), // filter

                    'htmlOptions'=>array('style'=>'text-align:center;min-width:60px;')

            ),

            array(

                    'class'=>'JToggleColumn',

                    'name'=>'visible', // boolean model attribute (tinyint(1) with values 0 or 1)

                    'filter' => array('0' => 'No', '1' => 'Yes'), // filter

                    'checkedButtonImageUrl'=>'/auth/images/check.png', // checked image

                    'uncheckedButtonImageUrl'=>'/auth/images/uncheck.png', // unchecked image

                    'checkedButtonLabel'=>'Uncheck this', // tooltip

                    'uncheckedButtonLabel'=>'Check this', // tooltip

                    'htmlOptions'=>array('style'=>'text-align:center;min-width:60px;')

    ),

    array(

        'class'=>'CButtonColumn',

    ),

),

)); ?>



Create action in your controller:




public function actionToggle($id,$attribute)

{

    if(Yii::app()->request->isPostRequest)

    {

        // we only allow deletion via POST request

        $model = $this->loadModel($id);

        $model->$attribute = !$model->$attribute;

        $model->save();


        // if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser

        if(!isset($_GET['ajax']))

            $this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));

        }

        else

        throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');

    }


?>



Don’t forget to add this action to controllers accessRules.

This is my first extension.

All suggestions are welcome!

GIT Repository

http://bitbucket.org/johonunu/jtogglecolumn

Man, this is incredibly useful for my project, but i can’t make it work.

I’ve done everything you said but i’m getting the message in the picture.

What am i doing wrong?

Yeah I also find this extension very useful for my current project.

Sadly it doesnt work with CArrayDataProvider as it always tries to read $data->primaryKey which is not available in CArrayDataProvider.

I’m pretty new to Yii and OOP in PHP in general, but I tried to fix this issue.

I also changed the way the column-data is provided.

In my case I needed to know the row-id (provided with $data[$this->grid->dataProvider->keyField]) and the column-id (using $data[$this->name]).

It may be a better solution to use another property than “name” for this… :)

Maybe someone else can use it or contribute a better solution…

In Main Class after :




 private $_assetsUrl;



Add:




 private $_isArrayData = false;



Add this to "public function init()" (this after the if-statements,before $this->initDefaultButtons)




        if (get_class($this->grid->dataProvider) === 'CArrayDataProvider')

            $this->_isArrayData = true;



In "protected function initDefaultButtons()", replace:




            $this->toggle_button = array(

                'url' => 'Yii::app()->controller->createUrl("toggle",array("id"=>$data->primaryKey,"attribute"=>"' . $this->name . '"))',

                'options' => array('class' => $this->name . '_toggle'),

            );




with:




        if ($this->_isArrayData) {

            $this->toggle_button = array(

                'url' => 'Yii::app()->controller->createUrl("toggle",array("id"=>$data[$this->grid->dataProvider->keyField],"attribute"=>$data[$this->name]))',

                'options' => array('class' => $this->name . '_toggle'),

            );

        }

        else {

            $this->toggle_button = array(

                'url' => 'Yii::app()->controller->createUrl("toggle",array("id"=>$data->primaryKey,"attribute"=>"' . $this->name . '"))',

                'options' => array('class' => $this->name . '_toggle'),

            );


        }



Hello everyone,

I am very happy I found this extension and I am using it in my project.

Unfortunately, I am having a very strange error. The extension does not work on table rows that have a datetime set to default "0000-00-00". This is my schema:

[font="Courier New"]




-------------------------------------------------------------------------------------------------

| content_id | index_id | active | name | content_url 	| description      | release_date | ...

-------------------------------------------------------------------------------------------------

| 1      	| 1    	| 0  	| KTK  | NULL        	| KTK Description  | 0000-00-00   | ...

| 2      	| 2    	| 0  	| VTV  | NULL        	| VTV Description  | 0000-00-00   | ...

| 3      	| 3    	| 0  	| RTP  | NULL        	| RTP Description  | 2012-06-15   | ...



[/font]

When I click the toggle icon on the CGridView for row #1 or #2, it does not work. When I click the toggle icon for #3, it works fine. If I add a date into #1’s “release_date” then toggling #1 works fine.

Can someone help me figure this out please? I am using Yii 1.1.10

Thank you very much!

EDIT:

Found the solution, in fact it was in the Extension page of Yii Wiki. The solution is to open up ToggleAction.php (or the SwitchAction.php) file and change:


$model->save();

to:


$model->save(false);

Hope this helps the next guy. Thank you for a great extension :)

I’m glad you found solution. I will correct it as soon as I have some time ;)

@johonunu:

I am having trouble achieving something with JToggleColumn. I would like that on every toggle, the action to be logged to a specified Log table in the database.

For example, I have 2 models: Contents and ContentsLog. I already have it working so that each time a record (in Contents model) is created/updated/deleted, the ContentsLog model is written a row. So, if a Contents record is created, a new row in ContentsLog is created at actionCreate() that reads something like “Content (XYZ) was created at 12:10 PM on July 7, 2012” (it’s divided into columns but I’m keeping it simple for sake of example).

I am still searching the right spot in JToggleColumn code where I could add this logging capability. I will report if I figure it out before you post :)

But please if you have any tips, let me know.

I appreciate the great plugin!

[EDIT]:

Wow! Figured it out! I cannot be the only Yii user who posts a question on the forum and then finds the answer a couple hours after. This feels so good. I guess it’s the power of Yii and developers like @johonunu. Anyway, on to my solution:

In the Contents controller, I added the following "logger" function:




public function dataLogger($logData)

{

  	$contentsLog=new ContentsLog;

  	$contentsLog->content_id = $logData["content_id"];

  	$contentsLog->user_id = $logData["user_id"];

  	$contentsLog->description = $logData["description"];


  	$contentsLog->validate(); // Validate the data against the ContentsLog model

  	if ( !$contentsLog->save() ) {

  	  	return false;

  	}else{

  	  	return true;

  	}

}



Then in the ToggleAction.php file, I modified the code to look like this:




public function run($id,$attribute) {

   	$logContent = array(); // This must be declared at the start of function

   	if(Yii::app()->request->isPostRequest)

   	{

   	   	// we only allow deletion via POST request

   	   	$model = $this->controller->loadModel($id);

   	   	$model->$attribute = ($model->$attribute==0)?1:0;


   	   	$logContent["actOrDeact"] = ($model->$attribute==0)?"deactivated":"activated";


   	   	if ( $model->save(false) )

   	   	{

   	   	   	# Compile log message

   	   	   	$logContent['content_id']=$model->content_id;

   	   	   	$logContent['user_id']=1; // Hard-coding user for now until I setup user management

   	   	   	$logContent['description']= 'Content "'.$model->name.

           	   	   	   	   	  	'" (#'.$model->content_id.

           	   	   	   	   	  	') was '.$logContent["actOrDeact"].

           	   	   	   	   	  	' by user "1" (#'.$logContent["user_id"].')';


   	   	   	if ( $this->controller->dataLogger($logContent) )

   	   	   	{

   	   	   	   	echo "DATA LOGGED FINE!!!"; // Just my quasi-debugging here, you can ignore this

   	   	   	}else{

   	   	   	   	echo "DATA NOT LOGGED FOR SOME REASON!!"; // Quasi-debugging here

   	   	   	}


   	   	   	// if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser

   	   	   	if(!isset($_GET['ajax']))

   	   	   	   	$this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));

   	}

   	else

   	   	throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');

}



I hope this helps someone who needs to include logging into the great JToggleColumn extension. As always, if more experienced developers have a better way to do this, please share your tips as I would love to make the code faster/shorter.

Happy coding!

Great! Nice to see some code examples for others to see. I am glad you like my extension ;)

Hi,

I am using this extension in Yii’s datagrid. However, whenever i toggle between column statuses, pagination and search criteria are reset and i am taken to page 1 again with clear filters. Can you please help me with that.