List filter (also using pagination)

I'm thinking what is the best way to create filters for a listing by some of the model attributes?

In prado you just have to create the dropdown boxes and the selected values are automaticaly re-selected after the postback.

Yii have some helper for this ?

CHtml::activeDropdownList() should be enough.

When you call $model->attributes=$_POST[ModelClass], the selected value will be assigned to the model and then when you use the model to generate the dropdown again, it automatically makes the selection.

So I have to create a model for the form containing the dropdownlistboxes filters?

You already have a model, don't you?

Not realy.

I have a list of students (ActiveRecords) and want to filter the list by the year they start studying in the school, or by gender.

So I was creating the dropdownlist directly in the form using CHtml::dropDownList.

I guess you said that I have to create a class that extends CFormModel to represent the filters like this:

class StudentFilterForm extends CFormModel


{


    public $year;


    public $gender;


    public $class;


}

Yes, that's right. While it looks cumbersome at first sight, an import benefit using a form model is that you can specify validation rules to ensure the correctness of input data. Of course, it also makes you able to use those active methods.

Thank's qiang, that fixed the problem with keeping the form values after postback.

Now I want to keep the filter when the page changes because when this happens, the filters are lost because there is no postback since the page numbers are just hyperlinks.

The only thing that comes to my mind is keeping the filter values in session or cookie.

Any idea?

Use a GET form to enclose the dropdown so that the selection will appear in the URL.

I started using GET and noticed the following:

1 - I had to manually put a hiddenfield named 'r' and value equal to the route I was using (secretaria.processoSelecaoCandidato/admin) because after submiting the form it was taking me to the index page. Shouldn't the framework do this when GET method is used?

2 - The filter worked when I pressed the submit button. I can see stuff like

"&FiltroCandidatoForm[ano]=2009" in the URL. But when changing pages, all the strings inside the backets are blank like "&FiltroCandidatoForm[]=2009". It's not maintaining the attributes.

Here is my form class:

class FiltroCandidatoForm extends CFormModel


{


    public $ano;


    public $segmento;


    public $serie;


    public $turno;


    public $nome='';


}

Here is my form in view:

<?php echo CHtml::form('','get'); ?>


<?php echo CHtml::hiddenField('r','secretaria.processoSelecaoCandidato/admin') ?>


<table class="dataGrid">


	<tr>


		<th class="filtro" align="center" colspan="2"><?php echo CHtml::submitButton('Aplicar filtros') ?></th>


		<th class="filtro" align="center"><?php echo CHtml::activeDropDownList($filtroCandidato,'ano',$optFiltroAno) ?></th>


		<th class="filtro" align="center"><?php echo CHtml::activeDropDownList($filtroCandidato,'segmento',$optFiltroSegmento,array('prompt'=>'')) ?></th>


		<th class="filtro" align="center"><?php echo CHtml::activeDropDownList($filtroCandidato,'serie',$optFiltroSerie,array('prompt'=>'')) ?></th>


		<th class="filtro" align="center"><?php echo CHtml::activeDropDownList($filtroCandidato,'turno',$optFiltroTurno,array('prompt'=>'')) ?></th>


		<th class="filtro" align="left"><?php echo CHtml::activeTextField($filtroCandidato,'nome',array('size'=>'30')) ?></th>


	</tr>


...

It's weird that submitting the form would bring you to index page. Could you please show me the generated HTML code about the form tag?

For 2, there is a bug in createUrl() that I just fixed. Thanks.

I used the following view code in the extension list page to deal with filtering by category:



<?php echo CHtml::form('','get'); ?>


Category: 


<?php 


	echo CHtml::dropDownList(


		'cat',


		isset($_GET['cat'])?(int)$_GET['cat']:0,


		CHtml::listData($categories,'id','name'),


		array(


			'empty'=>'All categories', 


			'submit'=>'',


		)); 


?>


</form>


Unlike yours, it is auto-postback and no model is used (because it is simpler).

Ok, thanks! the pagination now works keeping the filters!

Here is the generated HTML code of the form tag without manually inserting the hidden field:

<form action="/~joao/yii/index.php?r=secretaria.processoSelecaoCandidato/admin" method="get"><table class="dataGrid"> 


	<tr> 


		<th class="filtro" align="center" colspan="2"><input type="submit" name="yt0" value="Aplicar filtros"/></th> 


		<th class="filtro" align="center"><select name="FiltroCandidatoForm[ano]" id="FiltroCandidatoForm_ano"> 


<option value="2010">2010</option> 


<option value="2009">2009</option> 


<option value="2008">2008</option> 


<option value="2007">2007</option> 


<option value="2006">2006</option> 


</select></th> 


		<th class="filtro" align="center"><select name="FiltroCandidatoForm[segmento]" id="FiltroCandidatoForm_segmento"> 


<option value=""></option> 


<option value="EI">EI</option> 


<option value="EF1">EF1</option> 


<option value="EF2">EF2</option> 


<option value="EM">EM</option> 


</select></th> 


		<th class="filtro" align="center"><select name="FiltroCandidatoForm[serie]" id="FiltroCandidatoForm_serie"> 


<option value=""></option> 


<option value="Maternal II">Maternal II</option> 


<option value="Pré I">Pré I</option> 


<option value="Pré II">Pré II</option> 


<option value="1º Ano">1º Ano</option> 


<option value="2º Ano">2º Ano</option> 


<option value="3º Ano">3º Ano</option> 


<option value="4º Ano">4º Ano</option> 


<option value="5º Ano">5º Ano</option> 


<option value="6º Ano">6º Ano</option> 


<option value="7º Ano">7º Ano</option> 


<option value="8º Ano">8º Ano</option> 


<option value="9º Ano">9º Ano</option> 


<option value="1º Ano EM">1º Ano EM</option> 


<option value="2º Ano EM">2º Ano EM</option> 


<option value="3º Ano EM">3º Ano EM</option> 


</select></th> 


		<th class="filtro" align="center"><select name="FiltroCandidatoForm[turno]" id="FiltroCandidatoForm_turno"> 


<option value=""></option> 


<option value="Manhã">Manhã</option> 


<option value="Tarde">Tarde</option> 


</select></th> 


		<th class="filtro" align="left"><input size="30" name="FiltroCandidatoForm[nome]" id="FiltroCandidatoForm_nome" type="text" value=""/></th> 


	</tr>


table continues... 

Since the method is GET, the part after ? in the action is ignored.

My development server is windows XP with apache 2.

Do I have to enable a extension or something?