How to add ajaxButton in the CGridView

No my code only works when using a seperate column of the type ‘raw’ with regular ajaxLinks in there (code posted in post #7)

If the Id is the primary key of the table that would be logical. Looking at your Action code it’s the value in SortOrder that should have changed, not the Id itself!

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 | Title | Sort Order

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

25 banana 2

72 citrus 3

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


Id | Title | Sort Order

25 banana 1 (click down button on this row, controller STILL receive Id as 38, it shud be 25)

38 apple 2

72 citrus 3

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…

Following your post #7 ajaxLink way, I am also getting the same problem…

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 something…

What am I doing wrong? Can you share your exact working codes?

I can’t believe this is happening only to me… Nobody did any page sorting on the grid before?

Please help…

Maybe this can give you some inspiration:

http://www.yiiframework.com/forum/index.php?/topic/8994-dropdown-for-pagesize-in-cgridview/

thanks mike for the inspiration… I learn about CClientScript and got a super dropdown list. :D

but still not very sure if it will help refresh the CDATA

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>



After I sort records and use ajax to load the page again, how to regenerate to CDATA above to reflect the sorted rows? Will CClientScript help to regenerate? if yes how do I write the registerScript codes?

Thanks.

Why do you want that? If you use jquery.live() to connect your event handler (which you do), you don’t need to re-attach on every response.

But I did not used any jquery.live() method… All the CDATA script above was AUTO generated by yii… My only code was :




          

    array(

      'type'=>'raw',

      'value'=>'CHtml::ajaxLink(CHtml::image("' . Yii::app()->request->baseUrl . '/images/uparrow.png","up",array("border"=>0)),Yii::app()->createUrl("/product/reposition"),array(

                "data"=>array(

                        "id"=>$data->Id,

                        "direction"=>"up",

                        "sortOrder" =>$data->SortOrder,

                        ),

                "update"=>"#profileGrid",

            ))." ".

            CHtml::ajaxLink(CHtml::image("' . Yii::app()->request->baseUrl . '/images/downarrow.png","down",array("border"=>0)),Yii::app()->createUrl("/product/reposition"),array(

                "data"=>array(

                        "id"=>$data->Id,

                        "direction"=>"down",

                        "sortOrder" =>$data->SortOrder,

                ),

                "update"=>"#profileGrid",

                                

            ));',   

    ), /*      



After I press on the sort button, the grid reload with a new order, but the references to the sort button (yt0,yt1) still refers to the earlier Id.

First time load


Id | Title | Sort Order

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

25 banana 2

72 citrus 3

CDATA

jQuery(’#yt0’).live(‘click’,function(){jQuery.ajax({‘data’:{‘id’:‘38’

jQuery(’#yt0’).live(‘click’,function(){jQuery.ajax({‘data’:{‘id’:‘25’

jQuery(’#yt0’).live(‘click’,function(){jQuery.ajax({‘data’:{‘id’:‘72’

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


Id | Title | Sort Order

25 banana 1 (click down button on this row, controller STILL receive Id as 38, it shud be 25)

38 apple 2

72 citrus 3

I need the yt0, yt1 in the CDATA to follow the new Id order too (25,38,72). Right now when I click on the sort button of 1st row (id=25) the controller receive the id as 38!! (previous sort order)

I am still very new to yii and jquery stuff…

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.

I would implement this without using ajaxLinks. Every single link needs a line of code to initialize. And you see the problem this creates when you update the grid content. Actually i never use them anywhere in my code. If you register a small javascript snippet instead, that connects a live handler to all links in a column (maybe mark them with a custom CSS class), you will only need one single javascript method that extracts the id of the clicked row, sends the request and updates the grid afterwards.

OK! I will give up on making the up/down sort button in ajax and move on with yii life! Mike and Tommy in this thread is absolutely 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…

Meanwhile… lets put this thread back into the context of the OP "How to add ajaxButton in the CGridView"

Tommy’s solution :

I tried this, but it only changes from Publish to Unpublish at the first click, after that it doesn’t change anymore… am I missing something?

I used this action in the controller for a quick test (I happened to have a field named Active in the Item table)




public function actionPublish()

{

  if(isset($_GET['id']))

  {

    $model = Item::model()->findByPK($_GET['id']);

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

    $model->update(array('Active'));

    echo $model->Active;

  }

  Yii::app()->end();

}



/Tommy

This one works at the back, but after I click the first time, the button turns from Unpublish to Publish never changes after subsequent clicks.

Can you explain how the below works? I suspect the line "title"=>"{$data->Active}"?"Unpublish":"Publish"

is not working because the first time it loads, all rows are "Unpublish" (which is not true)

Tried to write code for eval in the line like this but can’t figure the correct syntax…

"title"=>"({$data->Active}==N)"?"Unpublish":"Publish"


'buttons'=>array(

  'pub'=>array(

    'options'=>'array("title"=>"{$data->Active}"?"Unpublish":"Publish", "id"=>"pub{$row}")',

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

    'ajax'=>'

      array(

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

        "data"=>array("id"=>$data->ItemId),

        "success"=>\'js:function(html){

          jQuery("#pub\'.$row.\'")

          .html((html>0)?"Unpublish":"Publish");

        }\',

      )

    ',

  ),

),

Also what is the meaning of (html>0) ? Should I change it to something like this :

.html(({$data->Active==1})?"Unpublish":"Publish")?

Thanks

It works when I change explicitly to these:




    array(

      'header'=>'Publish',

      'class'=>'ButtonColumnEx2',

      'template'=> '{pub}',

      'buttons'=>array(

        'pub'=>array(

          //'options'=>'array("title"=>"{$data->Status}"?"Unpublish":"Publish", "id"=>"pub{$row}")',

          'options'=>'array("title"=>"{$data->Status}", "id"=>"pub{$row}")',

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

          'ajax'=>'

            array(

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

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

              //"success"=>\'js:function(html){

              //  jQuery("#pub\'.$row.\'").html(htm>0)?"Unpublish":"Publish");

              //}\',              

              "success"=>\'js:function(html){

                $currentStatus = jQuery("#pub\'.$row.\'").html();

                jQuery("#pub\'.$row.\'").html(($currentStatus=="Publish")?"Unpublish":"Publish");

              }\',

              }\',

            )

          ',

        ),

      ),

    ),



In the ButtonColumnEX




    if(!isset($options['title']))  //*** was here before

      $options['title']=$label;    //*** 

    elseif (!isset($button['label']))

      $label = $options['title'];


/** ADDED THIS ***/

    if ($options['title']=="N")

    {

      $options['title'] = "Publish";

      $label = "Publish";

    } 

    elseif ($options['title']=="A") 

    {

      $options['title'] = "Unpublish";

      $label = "Unpublish";

    }  

/** ADDED THIS ***/



Any other better way?

I don’t know why your example works with

‘options’=>'array(“title”=>"{$data->Status}"?“Unpublish”:“Publish”,

and

jQuery("#pub\’.$row.\’").html(htm>0)?“Unpublish”:“Publish”);

Can you elaborate? Thanks, just trying to learn the expert way to code…

It was roughly explained in post #11

Perhaps our use cases differs a bit. My is just hypothetical.

So if the record is marked Active in the db, the label will initially become "Unpublish".

And as you can see in the controller action example, the updated state of Active is returned. It is then used in the test "html>0" to decide which label to choose.




.html((html>0)?"Unpublish":"Publish");



(you have a typo in the quoted text above)

/Tommy

Here is how I did it: http://www.yiiframework.com/forum/index.php?/topic/10639-solved-ajax-update-in-cgridview/page__view__findpost__p__59120

Your solution looks good and should be easier to implement (e.g. for a CDataColumn). But will it work for CButtonColumn? Without investigating further, I think the $.fn.yiiGridView.update() may be used.

If I understand your solution correctly, there is two performance drawbacks, though. You have to do two request/response cycles and you have to request the complete grid instead of a numeric return code (or short string).

/Tommy

I’ve no idea if it will work for a CButtonColumn. I made it so that it works with just a hyperlink.

I don’t know about performance, but I would welcome any improvements to this code! I think you’re right when you say it has to request the whole grid. I think ideally we want to request only the value that has been updated and display the new value in the column.

let me add one more alternate solution to this topic.

what i wanted to do is really simple.

  • just an ajax button

  • no JS needed.

first, you need a new button column class




class QCAjaxButtonColumn extends CButtonColumn

{

	protected function initDefaultButtons()

	{

		parent::initDefaultButtons();


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

		{

	  	      $csrfTokenName = Yii::app()->request->csrfTokenName;

	 	      $csrfToken = Yii::app()->request->csrfToken;

		      $csrf = "\n\t\tdata:{ '$csrfTokenName':'$csrfToken' },";

		}

		else

			$csrf = '';


		foreach($this->buttons as $id=>$button)

		{

		    if( ($id != 'view') && ($id != 'update') && ($id != 'delete') )

           	    {

		        // not default buttons ( user defined )

		        if( isset($button['ajax']) && ($button['ajax']) )

    		       {


		           $this->buttons[$id]['click']=<<<EOD

function() {

	$.fn.yiiGridView.update('{$this->grid->id}', {

		type:'POST',

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

		success:function() {

			$.fn.yiiGridView.update('{$this->grid->id}');

		}

	});

	return false;

}

EOD;


    		        }

                    }

		}

	}


}



and in grid view…




        array(

            'class'=>'QCAjaxButtonColumn',

            'template'=>'{button1} {button2}',

            'buttons'=>array(

                'button1'=>array(

                    'label'=>'some label',

                    'ajax'=>true,

                    'url'=>'Yii::app()->controller->createUrl("your url",array("id"=>$data->primaryKey))',

                ),

                'button2'=>array(

                    'label'=>'other label',

                    'ajax'=>true,

                    'url'=>'Yii::app()->controller->createUrl("your url",array("id"=>$data->primaryKey))',

                ),

            ),

        ),



I know this implementation is not beautiful, but this works fine to me.

WORKS GREAT!