Disable checkbox in CCheckBoxColumn based on attribute value

Hi,

I have a CCheckBoxColumn in a CGridView widget. I am trying to set the html option ‘disabled’ to true or false for a checkbox based on some condition on the value of a model attribute. There is no property in this class to do this directly (something like ‘CCheckBoxColumn.checked’), so I tried using checkBoxHtmlOptions like these:




			'checkBoxHtmlOptions' => array(

				'disabled' => ClassX::model()->isDisabled('$data->amount'),

			),



and




			'checkBoxHtmlOptions' => array(

				'disabled' => 'ClassX::model()->isDisabled($data->amount)',

			),



But these don’t work because local variables (dataprovider/data) can’t seem to be accessed inside checkBoxHtmlOptions. Please advise on how I could proceed.

Thank you.

But…

there is the checked property - http://www.yiiframework.com/doc/api/1.1/CCheckBoxColumn#checked-detail

What I meant was there is no property to set ‘disabled’ to true/false like there is for ‘checked’ in CCheckBoxColumn. By disabling, the user should not be allowed to click on the checkbox at all; I want to set this html option based based on an attribute value for that particular row ($data->amount in the example).

Ops sorry I misunderstood the post…

the checkBoxHtmlOptions is not evaluated on runtime, like value and checked, that’s why your code is not working…

to make this work you can extend the checkboxcolumn… your class would have just the renderDataCellContent() method where you would call the evaluateExpression()… .check the current source code to see how it’s used for the ‘value’ and ‘checked’ properties…

No problem.

Exactly what I thought would be an option - to extend the CCheckBoxColumn::renderDataCellContent() to include the functionality I want. The reason I was hesitant and checked with the community to see if there are other solutions is that if some future release of Yii adds more functionality to this method and I continue to use my derived class, I might miss out and branch off. Will continue to monitor this class closely in future releases then :)

Thanks for your prompt responses, mdomba.

EDIT: Never mind my comment about extending and future releases; I should be able to do this without any issues or worries about future releases if I just call the parent method appropriately after setting the html option correctly in my derived class.

Yes… to have minimal impact on future changes in the base class… you can just add a new property "disabled" and after evaluating it… call the parent methods…

something like this:




class myCheckBoxColumn extends CCheckBoxColumn

{

	public $disabled;

	protected function renderDataCellContent($row,$data)

	{

		if($this->disabled!==null)

			$this->checkBoxHtmlOptions['disabled']=$this->evaluateExpression($this->disabled,array('data'=>$data,'row'=>$row));

		parent::renderDataCellContent($row,$data);

	}

}



This way you can use code like this:




'columns'=>array(

   'id',

   'name',

   array(

  	'class'=>'myCheckBoxColumn',

  	'name'=>'checkfield',

  	'disabled'=>'$data->checkfield',

   ),

)



Thanks for the detailed response. I did get it working.

There is one issue though - the checkbox gets disabled correctly and I am unable to check/uncheck if I click only on the checkbox. But if I click anywhere on the data row whose checkbox is disabled or click on the check all button at the top, the checkbox that is disabled toggles. I think this is a functionality of the javascript code in the CCheckBoxColumn::init() but I am not too sure. How would I change the behavior to ignore toggling of disabled checkboxes when clicking the data row or the check all button?

I checked the _POST attributes and the disabled values don’t show up, so functionality is fine per se.

Another question - is there a way to define a header for the checkbox column, something like ‘Check All/Uncheck All’, above or below the checkbox?

Yes, this is js / jQuery code in jquery.yiigridview.js… but not sure how to solve this…

The "check all" checkbox in the header is displayed if you are in multiple selection mode… check the doc first paragraph - http://www.yiiframework.com/doc/api/1.1/CCheckBoxColumn

Ok. Will try to look through the js code to see if I can figure something out.

With the ‘check all’ checkbox, I meant to ask if there is a way to display a text such as ‘Check/Uncheck All’ in the header (in addition to the checkbox) in multiple selection mode.

I found a solution that would ignore toggling of disabled checkboxes when clicking the data row or the check all button in CGridView when using CCheckBoxColumn.

I had selectableRows=>2 for the CGridView widget and nothing for my extended class for CCheckBoxColumn. Instead, I set selectableRows=>2 in the latter (and removed it in the former) which resulted in a couple of things:

  1. As the CCheckBoxColumn::selectableRows documentation says, it is null by default in which case it assumes the value set for CGridView::selectableRows. By setting the value to 2, the user can no longer select a checkbox by clicking on the data row, which was one of the two things I wanted.

  2. In order to ignore toggling of disabled checkboxes when clicking the check/uncheck all button, I made the following code change in CCheckBoxColumn::init(). Changed


$('#{$this->id}_all').live('click',function() {

	var checked=this.checked;

	$("input[name='$name']").each(function() {this.checked=checked;});

});



to


$('#{$this->id}_all').live('click',function() {

	var checked=this.checked;

	$("input[name='$name']").each(function() {if(!this.disabled) { this.checked=checked; } });

});



The above will work only if selectableRows value is set to 0, 1 or 2 because the init() code would return without executing the jquery code otherwise.

The issue is that I don’t if and how I could extend the init() method to have this changed callback functionality. For lack of other options, am just overwriting (and not extending) the init() method in my derived class - this is both sub-optimal and risky w.r.t future releases.

Please advise as to what the optimal way to address this issue is? Should this be a code change in the framework itself or is there a cleaner way for me to extend the method?

You can fill an issue and ask for implementation of the hidden property in CCheckBoxColumn - http://code.google.com/p/yii/issues/entry

You can even reference this thread in the issue…

If more users request that feature (by starring your issue)… we will try to add it…

First, I would like to thank the solution.

I did everything that is described and worked perfectly.

I only had one problem. I had a button that deletes all the records selected in the grid, but after the changes do not work anymore.

The command $. Fn.yiiGridView.getSelection (\ ‘table-grid \’) does not return anything.

You know how to solve this problem?

Thanks!!!!!!

Where is the issue #?

I am having the exact same problem, and I need to vote on the implementation.

Why don’t you just use a conditional class? Example:


'columns' => array(

	array(

		'id' => 'id',

		'class' => 'CCheckBoxColumn',				

		'selectableRows' => 50,

		'cssClassExpression' => '$data->disabled?"hidden":""',

	),



The generated code would be something like:




<td class="checkbox-column hidden">

    <input type="checkbox" name="id[]" id="id_0" value="5712">

</td>



Then you apply a CSS like:


td.hidden input{

	display:none;

}