Custom paging with CListView

Hi Yiiers :)

I am using standard CListView widget to show all elements of ActiveRecord model:




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

	'dataProvider'=>$dataProvider,

	'itemView'=>'_view',

)); ?>



Standard paging only shows one element per line. What if I want to customize paging, so at least three elements will be shown per line, in that case I will be able to show more elements on one page, it’s already implemented here:

http://www.yiiframework.com/extensions/?page=6&sort=comments.desc

Thanks for your help.

up in the air :) Quite keen to know how to do that, wasn’t able to find it in documentation.

There was a tip about this but I couldn’t find it today.

Anyway, I tried it

Select a customized css class for items instead of ‘items’




'itemsCssClass'=>'items-float',



CSS file (I use a copy of framework/zii/widgets/assets/listview/styles.css plus three image files needed by the CSS)




.list-view .items-float .view

{	

  width: 200px;

  height: 200px;

  float:left;   /* <--- this will make the items float */

}



You might also need this to place the pager on it’s own line:

clear: both;

(not a CSS expert)

/Tommy

Hi Tommy,

Thanks for your CSS tip, but it looks like not CSS issue to me, I know how to position all elements to the left, it’s more like a pager issue. Look what I am after:

Let’s imagine I have 18 elements in CListView. If I am showing nine per page according to your css solution pagie will look like this:

element-1 element-2 element-3 element-4 element-5 element-6 element-7 element-8 element-9

But what I need is this:

element-1 element-2 element-3

element-4 element-5 element-6

element-7 element-8 element-9

This is exactly why I pointed out on this link with Yii extensions. It’s implemented there.

Thanks for your reply anyway.

What max pointed out is exaclty what you need.

You have to create a div contaner for example of 610 pixel:




<div style="width: 600px;">

<... CListWiew ...>

<div style="clear:both;"></div>

</div>




This container will make so that the fourth div will not have place on the left and will authomatically go to new line.

Don’t forget a clear div after the list view.

I can understand how CSS part should work in this case, but I want to know how CListView will know where to put this <div style="clear:both;"></div>,because it should run through 3 elements and put this cler:both div, then run through another three elements and put this div again. Do you understand what I am saying?

Here is my code




Controller:


	public function actionIndex()

	{

		$dataProvider=new CActiveDataProvider('model');

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

			'dataProvider'=>$dataProvider,

		));

	}

index.php View:


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

	'dataProvider'=>$dataProvider,

	'itemView'=>'_view',

        'template'=>'{sorter}<br />{pager}{items}{pager}',

        'enableSorting' => true,

        'sortableAttributes'=>array(

            'name'=>'By name',

        ),

)); ?>


CListView view file(_view.php) - representing each element


<div class="listing_container">

    <span class="listing_profile_pic">

        <img alt="<?=$data->name?>" class="img3" src="<?php echo Yii::app()->request->baseUrl; ?>/images/<?php echo $data->image_name; ?>" title="<?=$data->name?>" height="<?=$data->image_height?>" width="<?=$data->image_width?>">

    </span>

<?php echo CHtml::link(CHtml::encode($data->name), array('view', 'id'=>$data->id),array('class'=>'listing_artist')); ?>

</div>



I can’t put <div class=“clear”>&nbsp;</div> into _view file because it represents each element and this clear div will be after each element. Any ideas?

you don’t have to put each 3 elements, the magic of float will do the trick.

The idea is that You have an external div with fixed width, and this width is exactly 3 times the width of the inner div.

In your index php you should do something like:




<div style="width: 600px;">




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

        'dataProvider'=>$dataProvider,

        'itemView'=>'_view',

        'template'=>'{sorter}<br />{pager}{items}{pager}',

        'enableSorting' => true,

        'sortableAttributes'=>array(

            'name'=>'By name',

        ),

)); ?>

<div style="clear:both;"></div>

</div>






And in your view something like:





<div class="listing_container" style="width: 200px; float: left;">

    <span class="listing_profile_pic">

        <img alt="<?=$data->name?>" class="img3" src="<?php echo Yii::app()->request->baseUrl; ?>/images/<?php echo $data->image_name; ?>" title="<?=$data->name?>" height="<?=$data->image_height?>" width="<?=$data->image_width?>">

    </span>

<?php echo CHtml::link(CHtml::encode($data->name), array('view', 'id'=>$data->id),array('class'=>'listing_artist')); ?>

</div>



That’s all.

You simply need:

A container 3 times bigger than the inner div

Each div with a fixed width

A clear both at the end

Try.

Dude, it’s working, perefect, and I undersood the logic behind that, thank you for the explanation.

I was always saying that: Русские программисты лучшие в мире.

I already tried but the pager still join the list if it not full… actually i want to create thumbnail and what was happen is like this…

if my list: thumb1 thumb2 thumb3 thumb4

         thumb5 thumb6 thumb7 thumb8


                [pager appear here]

but if my list : thumb1 thumb2 thumb3 thumb4

              thumb5 thumb6 [pager appear here]

this is my code :


<?php   

		$dataProvider = new CActiveDataProvider(Picture, array(

			'criteria'=>array(

			    'condition'=>'ajaran_id='.$model->id,

				'order'=>'id ASC',

			),

			'pagination'=>array(

				'pageSize'=>12,

			),

		));

 ?>

 

<div style="width: 600px;">

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

            'dataProvider'=>$dataProvider,

            'itemView'=>'_picView',

         )); 

    ?>

<div style="clear:both;"></div>

</div>

and this is my view :


<div style="width: 150px; float: left;">

    <span>

        <img alt="<?php echo $data->filename; ?>" src="<?php echo Yii::app()->baseUrl; ?>/images/gallery/ajaran/<?php echo $data->ajaran_id; ?>/tmb/t_<?php echo $data->filename; ?>" title="<?php echo $data->filename; ?>">

    </span>

</div>

anything i left…? thanks in advance…

Hi all,

some time ago i’ve solved similar issue by extending CListView class to build a table with needed number of columns.

My solution is old and not very elegant, but maybe it will be usfeul for you as example.




<?php


Yii::import('zii.widgets.CListView');


/**

 * Extension for CListView for displaying items in table columns.

 *

 */

class MColumnListView extends CListView {


  /**

   * @var integer number of columns to display items in.

   */

  public $columns=2;


  public $itemsTagName='table';


  public $itemsCssClass='items-table';


  public $emptyText='';




	/**

     * Renders the data item list.

     */

	public function renderItems() {

		echo CHtml::openTag($this->itemsTagName,array('class'=>$this->itemsCssClass, 'cellspacing'=>'0'))."\n";


		$data=$this->dataProvider->getData();


		if(($n=count($data))>0) {

			$owner=$this->getOwner();

			$render=$owner instanceof CController ? 'renderPartial' : 'render';

			$cellWidth = floor(100 / $this->columns) . '%';

			$j=0;

			foreach($data as $i=>$item) {

		  	//first item in row

		  	if ( ($j % $this->columns) === 0 ) {

				echo CHtml::openTag('tr');

		  	}


				$data=$this->viewData;

				$data['index']=$i;

				$data['data']=$item;

				$data['widget']=$this;


				echo CHtml::openTag('td', array('width'=>$cellWidth));

				$owner->$render($this->itemView,$data);

				echo CHtml::closeTag('td');


				//last item in row

				if( ($j % $this->columns) === ($this->columns-1) ) {

					echo CHtml::closeTag('tr');

				}

				//last item in list

				elseif ( $j === ($n-1) ) {

			  	//output needed amount of empty td-tags

			  	$columnsLast = $j % $this->columns + 1;

			  	for ($z=$columnsLast; $z<$this->columns; $z++) {

					echo CHtml::tag('td');

			  	}

			  	echo CHtml::closeTag('tr');

				}

				$j++;

			}

		}

		else {

			$this->renderEmptyText();

		}


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

	}


}



Hm, looks like you took a very long and as you mentioned not very elegant way to achive the same thing just putting something like

<?php

&#036;column_count = 2;


if( (&#036;index % &#036;column_count) == 0 &amp;&amp; &#036;index&#33;=0)


{ 


	echo '&lt;/tr&gt;&lt;tr style=&quot;border: 0px&quot;&gt;';


}


echo '&lt;td style=&quot;border: 0px; width: '.floor(100.0/&#036;column_count).'%&quot;&gt;';

?>

in the listview page. This way you dont need to extend (break imp) the CListView class.

This works really well, however it would be nice to know how to pass a variable such as the column_count to the CListView.

does anyone know how to do this?

To answer my own question, seems like viewData can be used to pass additional arguments!