CDetailView - display attribute row upon condition

In my CDetailView I want to display an attribute row only if it matches a given condition, for example:


'attributes'=>array(

	$model->event_type==1 ? 'event_type' : null,

),

The problem is that a row is still displayed for the ‘null’ value.

If you don’t want rows for certain condition… then use that condition in the SELECT/criteria/dataprovider to get them out… not in the CGridView…

CDetailView or CGridView?

CGridView -> CDataColumn has a ‘visible’ property

CDetailView -> ‘nullDisplay’ property sets the text to be displayed when an attribute value is null. Defaults to “Not set”.

CDetailView (sorry, I’ve updated the post)

Setting nullDisplay is not the solution, as it will still display a row.

i´ve made a small modification to CDetailView:




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

	'data'=>$model,

	'attributes'=>array(

                ...

		array(

			'label'=>'ID',

			'type'=>'raw',

                        'value'=>$model->id,

			'visible'=> false, <-----------

		),

                ...

	),

        ));






class CDetailView2 extends CWidget

{

	private $_formatter;

	public $data;

	public $attributes;

	public $nullDisplay;

	public $tagName='table';

	public $itemTemplate="<tr class=\"{class}\"><th>{label}</th><td>{value}</td></tr>\n";

	public $itemCssClass=array('odd','even');

	public $htmlOptions=array('class'=>'detail-view');

	public $baseScriptUrl;

	public $cssFile;

	public function init()

	{

		if($this->data===null)

			throw new CException(Yii::t('zii','Please specify the "data" property.'));

		if($this->attributes===null)

		{

			if($this->data instanceof CModel)

				$this->attributes=$this->data->attributeNames();

			else if(is_array($this->data))

				$this->attributes=array_keys($this->data);

			else

				throw new CException(Yii::t('zii','Please specify the "attributes" property.'));

		}

		if($this->nullDisplay===null)

			$this->nullDisplay='<span class="null">'.Yii::t('zii','Not set').'</span>';

		$this->htmlOptions['id']=$this->getId();


		if($this->baseScriptUrl===null)

			$this->baseScriptUrl=Yii::app()->getAssetManager()->publish(Yii::getPathOfAlias('zii.widgets.assets')).'/detailview';


		if($this->cssFile!==false)

		{

			if($this->cssFile===null)

				$this->cssFile=$this->baseScriptUrl.'/styles.css';

			Yii::app()->getClientScript()->registerCssFile($this->cssFile);

		}

	}


	public function run()

	{

		$formatter=$this->getFormatter();

		echo CHtml::openTag($this->tagName,$this->htmlOptions);


		$n=is_array($this->itemCssClass) ? count($this->itemCssClass) : 0;

		foreach($this->attributes as $i=>$attribute)

		{

			if(is_string($attribute))

			{

				if(!preg_match('/^([\w\.]+)(<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/sad.gif' class='bbc_emoticon' alt=':(' />\w*))?(<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/sad.gif' class='bbc_emoticon' alt=':(' />.*))?$/',$attribute,$matches))

					throw new CException(Yii::t('zii','The attribute must be specified in the format of "Name:Type:Label", where "Type" and "Label" are optional.'));

				$attribute=array(

					'name'=>$matches[1],

					'type'=>isset($matches[3]) ? $matches[3] : 'text',

				);

				if(isset($matches[5]))

					$attribute['label']=$matches[5];

			}


			$tr=array('{label}'=>'', '{class}'=>$n ? $this->itemCssClass[$i%$n] : '');

			if(isset($attribute['cssClass']))

				$tr['{class}']=$attribute['cssClass'].' '.($n ? $tr['{class}'] : '');


			if(isset($attribute['label']))

				$tr['{label}']=$attribute['label'];

			else if(isset($attribute['name']))

			{

				if($this->data instanceof CModel)

					$tr['{label}']=$this->data->getAttributeLabel($attribute['name']);

				else

					$tr['{label}']=ucwords(trim(strtolower(str_replace(array('-','_','.'),' ',preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $attribute['name'])))));

			}


			if(!isset($attribute['type']))

				$attribute['type']='text';

			if(isset($attribute['value']))

				$value=$attribute['value'];

			else if(isset($attribute['name']))

				$value=CHtml::value($this->data,$attribute['name']);

			else

				$value=null;


			$tr['{value}']=$value===null ? $this->nullDisplay : $formatter->format($value,$attribute['type']);


/* begin */

			if (!isset($attribute['visible']))

			{

				echo strtr(isset($attribute['template']) ? $attribute['template'] : $this->itemTemplate,$tr); 

			}

			elseif ( $attribute === true )

			{

				echo strtr(isset($attribute['template']) ? $attribute['template'] : $this->itemTemplate,$tr); 

			}

/* end */


		}


		echo CHtml::closeTag($this->tagName);

	}


	public function getFormatter()

	{

		if($this->_formatter===null)

			$this->_formatter=Yii::app()->format;

		return $this->_formatter;

	}




	public function setFormatter($value)

	{

		$this->_formatter=$value;

	}

}



BUMP. Any simpler solution?

you can extend CDetailView or just think dynamic arrays!

start with a basic array e.g. $attributes = array(‘id’, ‘name’) then use if/else to add the attributes you want e.g. if(whateveris == true/false) $attributes[] = ‘fieldxxx’ or $attributes[] = array(‘label’=>‘ID’…);


$this->widget('zii.widgets.CDetailView2', array('data'=>$model, 'attributes'=>$attributes....)

If I am understanding your question correctly you should be able to call a function declared in your model to handle the logic for you and return value.

cheers,

bettor

No basically what I’m saying is for some records I want the attribute to be displayed and for some records I don’t want that attribute to be displayed.

I tried doing the conditional IF statement within the attributes array but it will still draw a "row" even if you tell it to return a null value.

in trunk:

http://code.google.com/p/yii/source/browse/trunk/framework/zii/widgets/CDetailView.php

<li>visible: whether the attribute is visible. If set to <code>false</code>, the table row for the attribute will not be rendered.

     * This option is available since version 1.1.5.&lt;/li&gt;

Cheers Flavio. This update works fine in that you can specify conditions to determine whether a row is visible or not, however the one slight issue is that if a row gets hidden then the following row has the same css class as the one above it, so you get two rows with the same colour.

Any fix for this?

at line: 169

change this:




$n=is_array($this->itemCssClass) ? count($this->itemCssClass) : 0;



to this:




$n=is_array($this->itemCssClass) ? count($this->itemCssClass) : 0; 	$j = 0;



at line: 186

change this:




$tr=array('{label}'=>'', '{class}'=>$n ? $this->itemCssClass[$i%$n] : '');



to this:




$j++; $tr=array('{label}'=>'', '{class}'=>$n ? $this->itemCssClass[$j%$n] : '');



here is working as expected after this changes

Thanks man that has worked. Actually I set $j to 1 so that the first row is blue (if $j = 0 the first row is grey)

you can change the detailview like

if($value===null)

		{


			echo '';


		}


		else


		{


			echo strtr(isset(&#036;attribute['template']) ? &#036;attribute['template'] : &#036;this-&gt;itemTemplate,&#036;tr);


		}


		 it works so similarly you can extend the detailview and use it anyway you want to

For future reference, just found a simpler way to handle this.

Make your attributes array outside of the CDetailView setup. Then, if your condition matches, add the appropriate fields to the $attributes array. Finally, set the CDetailView attributes property to your $attributes array.

Please do like this -


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

    'data'=>$model,

    'attributes'=>array(

        'id',

	'Person',

        array(

	   'name'=>'Status',

	   'type'=>'raw',

	   'value'=>(CHtml::encode($model->Status)==0)? "<span class=\"label label-important\">Inactive</span>":"<span class=\"label label-success\">Active</span>",

	),

    ),

));