Need CGridView examples to move record up/down

Hi,

I have been trying to understand cgridview and found some very useful filtering, formatting type, etc but cannot find what I need :

  1. to have CGridView with small up/down arrows to move the records sort order up and down?

  2. to create my own buttons inside the columns (like tick to publish/unpublish record)

  3. a tick box on the start of the record with a tick all at the title row

Any examples on these commonly used functions?

Thanks

Regarding (2) you may be interested in this.

/Tommy

Hi Tommy

Thanks but I do not know where to put the ‘buttons’ definition…

this doesn’t work

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

'id'=&gt;'product-grid',


'dataProvider'=&gt;&#036;dataProvider,


'columns'=&gt;array(


	'Id',


	'ShortTitle',


	'ShortDescription',


array(


  'name'=&gt;'SortOrder',


  'value'=&gt;'&quot;&lt;input type=&#092;&quot;text&#092;&quot; value=&#092;&quot;&quot; . &#036;data-&gt;SortOrder . &quot;&#092;&quot; &gt;&quot;',


  'type'=&gt;'raw',


),


array(     


 'buttons'=&gt;array(


    'up'=&gt;array(


        'label'=&gt;'up',


        'imageUrl'=&gt;Yii::app()-&gt;request-&gt;baseUrl . '/images/uparrow.png',


        'url'=&gt;'Yii::app()-&gt;createUrl(&quot;/item/reposition&quot;)',


        'ajax'=&gt;'


          array(


            &quot;url&quot;=&gt;Yii::app()-&gt;createUrl(&quot;/item/reposition&quot;),


            &quot;data&quot;=&gt;array(&quot;id&quot;=&gt;&#036;data-&gt;Id,&quot;direction&quot;=&gt;&quot;up&quot;,),


            &quot;update&quot;=&gt;&quot;#profileGrid&quot;


          )


        ',


      ),


    'down'=&gt;array(


        'label'=&gt;'down',


        'imageUrl'=&gt;Yii::app()-&gt;request-&gt;baseUrl . '/downarrow.png',


        'url'=&gt;'Yii::app()-&gt;createUrl(&quot;/item/reposition&quot;)',


        'ajax'=&gt;'


          array(


            &quot;url&quot;=&gt;Yii::app()-&gt;createUrl(&quot;/item/reposition&quot;),


            &quot;data&quot;=&gt;array(&quot;id&quot;=&gt;&#036;data-&gt;Id,&quot;direction&quot;=&gt;&quot;down&quot;,),


            &quot;update&quot;=&gt;&quot;#profileGrid&quot;


          )


        ',


      ),


    ),  


  ),





	array(


		'class'=&gt;'CButtonColumn',


	),


),

)); ?>

Hi Tommy

Thanks but I do not know where to put the ‘buttons’ definition…

this doesn’t work

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

'id'=&gt;'product-grid',


'dataProvider'=&gt;&#036;dataProvider,


'columns'=&gt;array(


	'Id',


	'ShortTitle',


	'ShortDescription',


array(


  'name'=&gt;'SortOrder',


  'value'=&gt;'&quot;&lt;input type=&#092;&quot;text&#092;&quot; value=&#092;&quot;&quot; . &#036;data-&gt;SortOrder . &quot;&#092;&quot; &gt;&quot;',


  'type'=&gt;'raw',


),


array(     


 'buttons'=&gt;array(


    'up'=&gt;array(


        'label'=&gt;'up',


        'imageUrl'=&gt;Yii::app()-&gt;request-&gt;baseUrl . '/images/uparrow.png',


        'url'=&gt;'Yii::app()-&gt;createUrl(&quot;/item/reposition&quot;)',


        'ajax'=&gt;'


          array(


            &quot;url&quot;=&gt;Yii::app()-&gt;createUrl(&quot;/item/reposition&quot;),


            &quot;data&quot;=&gt;array(&quot;id&quot;=&gt;&#036;data-&gt;Id,&quot;direction&quot;=&gt;&quot;up&quot;,),


            &quot;update&quot;=&gt;&quot;#profileGrid&quot;


          )


        ',


      ),


    'down'=&gt;array(


        'label'=&gt;'down',


        'imageUrl'=&gt;Yii::app()-&gt;request-&gt;baseUrl . '/downarrow.png',


        'url'=&gt;'Yii::app()-&gt;createUrl(&quot;/item/reposition&quot;)',


        'ajax'=&gt;'


          array(


            &quot;url&quot;=&gt;Yii::app()-&gt;createUrl(&quot;/item/reposition&quot;),


            &quot;data&quot;=&gt;array(&quot;id&quot;=&gt;&#036;data-&gt;Id,&quot;direction&quot;=&gt;&quot;down&quot;,),


            &quot;update&quot;=&gt;&quot;#profileGrid&quot;


          )


        ',


      ),


    ),  


  ),





	array(


		'class'=&gt;'CButtonColumn',


	),


),

)); ?>

I tried it like this but it show the CButtonColumn view,edit,del buttons

	[b]array(


		'class'=&gt;'ButtonColumnEx',[/b]





  'buttons'=&gt;array(


    'up'=&gt;array(


        'label'=&gt;'up',


        'imageUrl'=&gt;Yii::app()-&gt;request-&gt;baseUrl . '/images/uparrow.png',


        'url'=&gt;'Yii::app()-&gt;createUrl(&quot;/item/reposition&quot;)',


        'ajax'=&gt;'


          array(


            &quot;url&quot;=&gt;Yii::app()-&gt;createUrl(&quot;/item/reposition&quot;),


            &quot;data&quot;=&gt;array(&quot;id&quot;=&gt;&#036;data-&gt;Id,&quot;direction&quot;=&gt;&quot;up&quot;,),


            &quot;update&quot;=&gt;&quot;#profileGrid&quot;


          )


        ',


      ),


    'down'=&gt;array(


        'label'=&gt;'down',


        'imageUrl'=&gt;Yii::app()-&gt;request-&gt;baseUrl . '/downarrow.png',


        'url'=&gt;'Yii::app()-&gt;createUrl(&quot;/item/reposition&quot;)',


        'ajax'=&gt;'


          array(


            &quot;url&quot;=&gt;Yii::app()-&gt;createUrl(&quot;/item/reposition&quot;),


            &quot;data&quot;=&gt;array(&quot;id&quot;=&gt;&#036;data-&gt;Id,&quot;direction&quot;=&gt;&quot;down&quot;,),


            &quot;update&quot;=&gt;&quot;#profileGrid&quot;


          )


        ',


      ),


    ),  


  ),

See the CGridView and CButtonColumn documentation.




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

    ...

    'columns'=>array(

        ...

        array(

            //'class'=>'CButtonColumn',

            'class'=>'CButtonColumnEx',

            'template'=>'{up} {down}',

            ...

        ),

    ),

));



/Tommy

Great I can see the buttons now… Still learning how to read the docs…:D

i’m not sure, but it seems like you haven’t changed the “template” property of CButtonColumn

its required in order to display additional buttons, like

‘{up} {down} {delete} {update} {view}’

please, take a look at the CButtonColumn reference link below:

http://www.yiiframework.com/doc/api/CButtonColumn#template-detail

hope it helps

regards!!

:)

I understand the template now. No problem in getting the buttons to appear.

Now my new problem is getting the ajax to work (based on Tommy’s solution). When I click on the button, nothing happens. To test the actionReposition, I have resort to the old way of reloading the whole page. Please help me with getting the ajax to work.

Here my code, I hid the ajax element




      array(

	'class'=>'ButtonColumnEx',

	'template'=>'{up}{down}',

      'buttons'=>array(

        'up'=>array(

            'label'=>'up',

            'imageUrl'=>Yii::app()->request->baseUrl . '/images/uparrow.png',

            'url'=>'Yii::app()->createUrl("/product/reposition", array("id" => $data->Id, "sortOrder" => $data->SortOrder, "direction" => "up",))',

            

            /*'ajax'=>'

              array(

                "url"=>Yii::app()->createUrl("/product/reposition"),

                "data"=>array("id"=>$data->Id,"direction"=>"up",),

                "update"=>"#profileGrid"

              )

            ',*/

          ),

        'down'=>array(

            'label'=>'down',

            'imageUrl'=>Yii::app()->request->baseUrl . '/images/downarrow.png',

            'url'=>'Yii::app()->createUrl("/product/reposition", array("id" => $data->Id, "sortOrder" => $data->SortOrder, "direction" => "down",))',

            /*'ajax'=>'

              array(

                "url"=>Yii::app()->createUrl("/product/reposition"),

                "data"=>array("id"=>$data->Id,"direction"=>"down",),

                "update"=>"#profileGrid"

              )

            ',*/

          ),

        ),  

      ),



Action

(Please let me know the better way to use the db objects and isset validation for all the variables, etc), i simply code based on whatever I know about yii now )




	public function actionReposition()

	{

	  if(isset($_GET['direction']) && 

            isset($_GET['sortOrder']) &&

            isset($_GET['id']) )

	  {

	    $direction=$_GET['direction'];

	    $sortOrder=(int)$_GET['sortOrder'];

	    $id=$_GET['id'];

			

      if ($direction=='up') {

        $newSortOrder = $sortOrder-1;

      } else if ($direction=='down') {

        $newSortOrder = $sortOrder+1;

      } 


      $connection=Yii::app()->db;

      

      $sql='SELECT Id from tproducts WHERE SortOrder = "' . $newSortOrder . '"';

      $command=$connection->createCommand($sql);

      $reader=$command->query();

      foreach($reader as $row) {

        $otherId = $row["Id"];

      }

      $sql='UPDATE tproducts SET SortOrder = "' . $newSortOrder . '" WHERE Id = "' . $id . '"';

      $command=$connection->createCommand($sql);

      $command->execute();

      if ($reader->getRowCount() > 0) {

        $sql='UPDATE tproducts SET SortOrder = "' . $sortOrder . '" WHERE Id = "' . $otherId . '"';

        $command=$connection->createCommand($sql);

        $command->execute();

      }

 		}

         

		$dataProvider=new CActiveDataProvider('Product', array(

      'criteria'=>array(

          'order'=>'SortOrder ASC',

        ),

      )

		);

		

		$this->render('index',array(

			'dataProvider'=>$dataProvider,

		));



Joe, I didn’t offer a complete solution, just a way to add buttons configured for ajax. You should be able to see the call in Firebug. As per the question that started the thread I referred you to, the intended controller action was to be named “reposition”.

To the best of my understanding you have to render and echo at least the updated grid content in this action. If the ‘update’ clause doesn’t work, try something like this




'$.fn.yiiGridView.update("'.$target_container.'");'

or

'$.fn.yiiGridView.update("#name-of-grid");'



/Tommy

Hi Tommy,

Sorry I am too new to ajax and yii to understand snippets :D I am hoping for actual examples. Anyway I now following toMeloos guide over here but still can’t get the button to work.

Instead of the extended ButtonColumnEx, I am following his examples by using the default CButtonColumn.

I am posting the same reply here now. Can you help to get it work?

Got this error, after clicking on the "up/down" buttons on the grid

Error 400

Invalid request. Please do not repeat this request again.

admin.php




<?php

  $this->renderPartial('_admin',array('dataProvider'=>$dataProvider,));

?>



_admin.php




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

	'id'=>'profileGrid',

	'dataProvider'=>$dataProvider,

	'columns'=>array(

		'Id',

		'Title',

    array(

      'class'=>'CButtonColumn',

      'buttons'=>array(

        'up'=>array(

            'label'=>'up',

            'imageUrl'=>Yii::app()->request->baseUrl . '/images/uparrow.png',

            'url'=>'Yii::app()->createUrl("/item/reposition")',

            'ajax'=>'

              array(

                "url"=>Yii::app()->createUrl("/item/reposition"),

                "data"=>array("id"=>$data->id,"direction"=>"up",),

                "update"=>"#profileGrid"

              )',

          ),

        'down'=>array(

            'label'=>'down',

            'imageUrl'=>Yii::app()->request->baseUrl . '/images/downarrow.png',

            'url'=>'Yii::app()->createUrl("/item/reposition")',

            'ajax'=>'

              array(

                "url"=>Yii::app()->createUrl("/item/reposition"),

                "data"=>array("id"=>$data->id,"direction"=>"down",),

                "update"=>"#profileGrid"

              )',

          ),

        ),

      'template'=> '{up} {down}',

    ),

),



itemController.php




public function actionReposition()

{

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

  {

    if(isset($_GET['direction']) && 

    isset($_GET['id']) )

    { 

      $direction=$_GET['direction'];

      $id=$_GET['id'];


      if ($direction=='up') {

        $newSortOrder = $sortOrder-1;

      } else if ($direction=='down') {

        $newSortOrder = $sortOrder+1;

      } 

      //** do my db stuff here **//


      $dataProvider=new CActiveDataProvider('Product', array(

          'criteria'=>array(

              'order'=>'SortOrder ASC',

            ),

         )

      );

    		

      $this->renderPartial('_admin',array('dataProvider'=>$dataProvider,));

        

    }

  }

  else

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

}



It looks like it is not detecting Yii::app()->request->isAjaxRequest. if remark this line,it does not detect $_GET[‘direction’] or $_GET[‘id’]

I just added my answer in the other thread

/Tommy

Can you tell me why the Id in js script is not referring to the current row Id after the ajax call?

Id is the primary key. But I need to parse in the right Id to the controller to update the new sort order.

I will make this clearer…

First time load


Id | Sort Order | Title

38 | 1 | apple (click down button on this row, controller receive Id as 38, so I can swap the sortorder)

25 | 2 | banana

72 | 3 | citrus

After click, the Ajax refreshed (correctly shown on the grid)


Id | Sort Order | Title

25 | 1 | banana (click down button on this row, controller STILL receive Id as 38, it shouldn’t it be 25?)

38 | 2 | apple

72 | 3 | citrus

When the controller still refers to the original Id(38) after the grid is reloaded, I cannot update the "banana(25)" Sort order…

I hope you understand what I am mean… Really need to get this working asap… thanks a lot…

The first time I click on a button on any line, the controller got the right Id. Subsequently after the grid reloaded, clicking on anywhere gives the same Id as the previous button click. It is as if the data->Id is cached or the CDATA script is not updated to reflect the new sort position…

I think we have a problem here. One affordable solution might be to repack the models adding an static positional id that will be conveyed to/from the grid. Then just change the pk attribute to reflect the up/down ordering. There still might be issues with grid sorting and pagination

Just thinking loud.

/Tommy

Maybe I will try posting it in the bugs section…

I think this CDATA is causing the problem as it is not being refreshed.

This is the html source on the first load




<script type="text/javascript">

/*<![CDATA[*/

jQuery(document).ready(function() {

jQuery('#profileGrid a.delete').live('click',function() {

	if(!confirm('Are you sure you want to delete this item?')) return false;

	$.fn.yiiGridView.update('profileGrid', {

		type:'POST',

		url:$(this).attr('href'),

		success:function() {

			$.fn.yiiGridView.update('profileGrid');

		}

	});

	return false;

});

jQuery('#profileGrid').yiiGridView({'ajaxUpdate':['profileGrid'],'ajaxVar':'ajax','pagerClass':'pager','loadingClass':'grid-view-loading','filterClass':'filters','tableClass':'items','selectableRows':1});

jQuery('#yt0').live('click',function(){jQuery.ajax({'data':{'id':'4','direction':'up','sortOrder':'0'},'url':'/myapp/admin.php/product/reposition','cache':false,'success':function(html){jQuery("#profileGrid").html(html)}});return false;});

jQuery('#yt1').live('click',function(){jQuery.ajax({'data':{'id':'4','direction':'down','sortOrder':'0'},'url':'/myapp/admin.php/product/reposition','cache':false,'success':function(html){jQuery("#profileGrid").html(html)}});return false;});

jQuery('#yt2').live('click',function(){jQuery.ajax({'data':{'id':'7','direction':'up','sortOrder':'0'},'url':'/myapp/admin.php/product/reposition','cache':false,'success':function(html){jQuery("#profileGrid").html(html)}});return false;});

jQuery('#yt3').live('click',function(){jQuery.ajax({'data':{'id':'7','direction':'down','sortOrder':'0'},'url':'/myapp/admin.php/product/reposition','cache':false,'success':function(html){jQuery("#profileGrid").html(html)}});return false;});

jQuery('#product-folder-grid a.delete').live('click',function() {

	if(!confirm('Are you sure you want to delete this item?')) return false;

	$.fn.yiiGridView.update('product-folder-grid', {

		type:'POST',

		url:$(this).attr('href'),

		success:function() {

			$.fn.yiiGridView.update('product-folder-grid');

		}

	});

	return false;

});

/*]]>*/

</script>



Subsequent reload do not change any of the #yt0, #yt1 rows…

How to regenerate to CDATA above to reflect the sorted rows after each ajax click?

Will CClientScript help to regenerate? if yes how do I write the registerScript codes?

Thanks.

can someone please confirm if this problem I am facing relates this issue being the jscript is not generated inside the div of the grid?

AjaxLinks with RenderPartial

CJuiDIalog and CGridView with ajaxLink return is set outiside the update div

AjaxLink call CJuiDialog which contains CGridView

Haven’t anyone tried doing a sort up/down button that move rows up and down (through ajax) in the grid before?

I tried even the simplest sample of publish/unpublish button in the posts above, but after the second click, every click thereafter still refers to the Clientscript outside the div of the grid.

I did tried the _renderPartial(‘view’,array(), false, TRUE) it generates clientscript in the div of the grid, but the results are not quite expected, Checking on firebug shows multiple loading of jquery.js resulting in the grid running a few times before it stop.

Other posts of this same issue

http://www.yiiframework.com/forum/index.php?/topic/10210-cgridview-ajax-button-not-storing-correct-values/

Need CGridView examples to move record up/down

How to add ajaxButton in the CGridView

If this is not already a problem like I make of it, I hope some expert here can work on a real working publish/unpublished and sort up/down buttons for the Cookbook…

If this is indeed an unsolvable issue without concrete workaround, please let me (or other newbies) know.

Sorry for all the trouble but this is my first experience with Yii and I am hitting this problem.

Just to explain what I think is the problem with the up/down buttons, have a look at the html source. If I understand the gridview correctly, first in the grid you will see a div starting like this


<div class="keys" style="display:none" ...

containing the pk values of each visible row.

Now, when you update the grid after moving one row, the above id’s and the id’s bound to the buttons would not match. That’s why I wrote (in #14) about a possible workaround in the controller: serve the grid same id’s regardless of the up/down change. That’s why I was thinking about “repacking” the AR models, one way or another, so that the id known to the grid never change, the pk would just be passed along as any attribute. With this approach (posting, saving, updating grid) this is the solution I can think of. Others might have a better suggestion.

A completely different approach would be to reorder the grid content in javascript only, optionally post the change to the controller. Either way, this isn’t easy and as said, modifications like this one might lead to other issues with paging and column sorting. I don’t know. (And I’m not trying to find out, at least not for the weeks to come.)

/Tommy

OK! I will give up on making the up/down sort button in ajax and move on with yii life! You are so right, I have tried so much to understand how .live and .bind works in relation to the ajax update of the grid after it is sorted. This just takes too much effort to move the rows up and down without messing with the ids known to the grid. For those looking to solve this, try Tommy’s advise and cookbook it please…

I suggested something in your other thread. Did you try it? Actually if done right, you don’t need much javascript code at all. But you should avoid using #ids. It’s much better to add a custom class to some elements, if you want to attach some functionality to them.