Yii Framework Forum: CListView sorter as Dropdown rather than links - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

CListView sorter as Dropdown rather than links a quick and dirty hack to achieve this... Rate Topic: -----

#1 User is offline   thyseus 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 300
  • Joined: 18-April 09
  • Location:Leipzig, Germany

Posted 04 June 2012 - 04:15 PM

Hey folks,

if you use a CListView and have too many sortable attributes, a Dropdown-List is much more user-friendly.
This can be "easy" achieved by extending CListView like in my little dirty hack here:

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

class CustomListView extends CListView
{
	public function renderSorter()
	{
		if($this->dataProvider->getItemCount()<=0)
return;

		
		$link = Yii::app()->controller->createUrl('');
		$modelname = $this->dataProvider->modelClass;

		$attributes = array();
		foreach($this->sortableAttributes as $name=>$label)
			$attributes[$label] = $this->dataProvider->model->getAttributeLabel($label);
		echo '<div style="float: right;">';
		echo 'Sort by: ';
		if(isset($_GET[$modelname.'_sort'])) {
			$selected = explode('.', $_GET[$modelname.'_sort']);
			$selected = $selected[0];
		}
		echo CHtml::dropDownList('sorter',
				isset($_GET[$modelname.'_sort']) 
				? $selected : 0, $attributes);
		echo CHtml::dropDownList('direction', isset($_GET['direction']) ? $_GET['direction'] : 'asc',
				array('asc' => 'Ascending', 'desc' => 'Descending'));
		echo '</div><div style="clear: both;"></div>';

		Yii::app()->clientScript->registerScript('sorter', "
				$('#sorter').change(function() {
					window.location.href = '".$link."?direction='+$('#direction').val()+'&".$modelname."_sort='+$(this).val() + '.' + $('#direction').val();
			
				$('#direction').change(function() {
					window.location.href = '".$link."?direction='+$('#direction').val()+'&".$modelname."_sort='+$('#sorter').val()+'.'+$(this).val();
					});
				");
	}

}		});



It is not perfectly elegant, but it works (for me). Let me know if there is an extension or something similar that solves this in a nicer way, or if you have any ideas on how to make this better.

Thanks - and enjoy!
0

#2 User is offline   yiqing95 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 586
  • Joined: 27-December 10
  • Location:china

Posted 04 June 2012 - 09:48 PM

:lol:

thanks for sharing , have some promotion room : ajax functionality
and expose some things as public variables :

echo '<div style="float: right;">'; ===> 'sorterContainerHtmlOptions' => array('style'=>'float:right'..);

echo 'Sort by: '; ===> echo $this->sortPrefixLable ;// or i18n
0

#3 User is offline   ibiz4 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 151
  • Joined: 26-November 10
  • Location:Indonesia

Posted 22 July 2012 - 09:47 PM

I have another approach, at least its little bit elegant for me. :D
<?php
Yii::import('zii.widgets.CListView');
class ListView extends CListView
{
	public $sortCriteria = array();

	/**
	 * Renders the sorter.
	 */
	public function renderSorter()
	{
		$controller	=	$this->getController();
		$url	=	$controller->createUrl($controller->getRoute());
		
		if($this->dataProvider->getItemCount()<=0 || !$this->enableSorting)
			return;
		echo CHtml::openTag('div',array('class'=>$this->sorterCssClass))."\n";
		echo $this->sorterHeader===null ? Yii::t('zii','Sort by: ') : $this->sorterHeader;
		echo CHtml::dropDownList(null,null,array(''=>'Select')+$this->sortCriteria,array(
									'id'=>'sortBy',
									'onchange'=>"$.fn.yiiListView.update('yw0',{ url:'".$url."?".ucfirst($controller->id)."_sort='+$('#sortBy').val()})"));
		
		echo $this->sorterFooter;
		echo CHtml::closeTag('div');
	}
}

?>


then provide some thing like this in your view

<?php
	$this->widget('ListView', array(
		.....
		'sortCriteria'=>array(
				'sold_date.desc'=>'Latest Sold',
				'sold_date'=>'First Sold')
	));
?>

WYSIWYG
(What Yii Serve is What You Get)
0

#4 User is offline   yugene 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 493
  • Joined: 08-August 09

Posted 24 July 2012 - 01:40 AM

Thanks for sharing, looks very neat.
0

#5 User is offline   Cam C 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 14
  • Joined: 12-June 11

Posted 02 August 2012 - 04:52 PM

Thank you very much for this ibiz4
It helped me out a lot.

I had made a change to get it to work properly.

My scenario
Controller: FeedbackController
Model: Referral

Problem
Although it would attempt to perform the sort on the CActiveDataProvider it would never update.
The issue boils down to attempting to use Feedback_sort in the url. This is wrong for my Provider. It should be Referral_sort

Solution
I changed this code:
'onchange'=>"$.fn.yiiListView.update('yw0',{ url:'".$url."?".ucfirst($controller->id)."_sort='+$('#sortBy').val()})"));

To this:
'onchange'=>"$.fn.yiiListView.update('yw0',{ url:'".$url."?".ucfirst($this->dataProvider->modelClass)."_sort='+$('#sortBy').val()})"));



I hope that helps anyone that comes across the same problem.

View Postibiz4, on 22 July 2012 - 09:47 PM, said:

I have another approach, at least its little bit elegant for me. :D
<?php
Yii::import('zii.widgets.CListView');
class ListView extends CListView
{
	public $sortCriteria = array();

	/**
	 * Renders the sorter.
	 */
	public function renderSorter()
	{
		$controller	=	$this->getController();
		$url	=	$controller->createUrl($controller->getRoute());
		
		if($this->dataProvider->getItemCount()<=0 || !$this->enableSorting)
			return;
		echo CHtml::openTag('div',array('class'=>$this->sorterCssClass))."\n";
		echo $this->sorterHeader===null ? Yii::t('zii','Sort by: ') : $this->sorterHeader;
		echo CHtml::dropDownList(null,null,array(''=>'Select')+$this->sortCriteria,array(
									'id'=>'sortBy',
									'onchange'=>"$.fn.yiiListView.update('yw0',{ url:'".$url."?".ucfirst($controller->id)."_sort='+$('#sortBy').val()})"));
		
		echo $this->sorterFooter;
		echo CHtml::closeTag('div');
	}
}

?>


then provide some thing like this in your view

<?php
	$this->widget('ListView', array(
		.....
		'sortCriteria'=>array(
				'sold_date.desc'=>'Latest Sold',
				'sold_date'=>'First Sold')
	));
?>


0

#6 User is offline   Mark O'Keeffe 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 8
  • Joined: 03-October 11

Posted 08 October 2012 - 09:56 AM

To add to ibiz4's answer, if you want the drop down list to stick on the selected value after the list has updated, just add the 'complete' option to the yiiListView.update JS:

    echo CHtml::dropDownList(null,null,array(''=>'Select')+$this->sortCriteria,array(
      'id'=>'sortBy',
      'onchange'=>"
        var filterVal = $('#sortBy').val();
        $.fn.yiiListView.update('yw0',{
          url:'".$url."?".ucfirst($controller->id)."_sort='+filterVal,
          complete: function(){ $('#sortBy').val(filterVal); }
        })")
    );

0

#7 User is offline   Mark O'Keeffe 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 8
  • Joined: 03-October 11

Posted 09 October 2012 - 05:22 AM

After attempting to add a 'fliter as you type' search filter using the above method, I have decided against the approach for the following reasons:

  • You do not get access to the $model object
  • The filter fields refresh (and empty) when the list view is updated
  • A combination of sort and filter cannot be used


Instead, I have opted for a simpler option that provides a little more flexibility, but could be improved...

My solution is to create a filter form directly above the listview, using the same yiiListView.update JavaScript method to reload the list view:

<?php $form=$this->beginWidget('CActiveForm', array(
    'id'=>'filter-form',
)); ?>

  <!-- Sort by dropdown list -->
  <?php echo CHtml::label('Sort by: ', 'Campaign_sort'); ?>
  <?php echo CHtml::dropDownList('Campaign_sort','',array(
    // Enter the sort options here
    'title' => 'Campaign Name',
    'start_date.desc' => 'Newest Campaigns First',
    'start_date' => 'Oldest Campaigns First',
  ),array(
    'prompt' => 'Select',
    'onchange'=>"
      $.fn.yiiListView.update('yw0',{
        data: $('#filter-form').serialize()
      })")
  ); ?>

  <!-- Find as you type filter for the 'title' attribute -->
  <?php echo $form->textField($model,'title',array(
    'onkeyup' => "
      $.fn.yiiListView.update('yw0', {
        data: $('#filter-form').serialize()
      });
    ")
  ); ?>

<?php $this->endWidget(); ?>
<?php
$this->widget('zii.widgets.CListView', array(
  'dataProvider'=>$model->search(),
  'itemView'=>'_listCampaign',
));
?>


Can anyone think of a neater way of integrating a filter form like this without having to explicitly generate it in the view alongside the list view?
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users