This tutorial shows how to filter CListView items by AJAX, and it's compatible with disabled JavaScript users
In my case this has been done to filter users list
In our view file we have something like this
$this->widget('zii.widgets.CListView', array( 'dataProvider'=>$dataProvider, 'itemView'=>'viewList', 'sortableAttributes'=>array( 'id'=>'cronologico', 'transaction' ), 'id'=>'ajaxListView', ));
We now add a form with a text field (remember to change form action), the value of the field get updated with the GET parameter
echo CHtml::beginForm(CHtml::normalizeUrl(array('message/index')), 'get', array('id'=>'filter-form')) . CHtml::textField('string', (isset($_GET['string'])) ? $_GET['string'] : '', array('id'=>'string')) . CHtml::submitButton('Search', array('name'=>'')) . CHtml::endForm();
and a JQuery script that sends AJAX request after a short delay (this reduces DB queries)
Yii::app()->clientScript->registerScript('search', "var ajaxUpdateTimeout; var ajaxRequest; $('input#string').keyup(function(){ ajaxRequest = $(this).serialize(); clearTimeout(ajaxUpdateTimeout); ajaxUpdateTimeout = setTimeout(function () { $.fn.yiiListView.update( // this is the id of the CListView 'ajaxListView', {data: ajaxRequest} ) }, // this is the delay 300); });" );
This is the controller action
public function actionIndex( $string = '' ) { $criteria = new CDbCriteria(); if( strlen( $string ) > 0 ) $criteria->addSearchCondition( 'username', $string, true, 'OR' ); $dataProvider = new CActiveDataProvider( 'User', array( 'criteria' => $criteria, ) ); $this->render( 'index', array( 'dataProvider' => $dataProvider ) ); }
I had to implement a more sophisticated filter for my offer CListView: selecting checkBoxes with integer value the search had to be filtered with an IN condition.
CheckBoxes get selected by the GET parameter
echo CHtml::checkBoxList('category', (isset($_GET['category'])) ? $_GET['category'] : '', $category[$key], array( 'class'=>'categoryFilter', ) );
Then i had to add this javaScript for the AJAX filtering
$('.categoryFilter').change(function(){ category = $('.categoryFilter').serialize(); $.fn.yiiListView.update( 'ajaxListView', {data: category} ); });
CheckBoxes GET parameters are variable (in my case up to 21) so I had to use an array in my controller.
public function actionIndex( $string = '', array $category = array() ) { $criteria = new CDbCriteria(); if( strlen( $string ) > 0 ) { $criteria->addSearchCondition( 'title', $string, true, 'OR' ); $criteria->addSearchCondition( 'description', $string, true, 'OR' ); } if( count( $category ) > 0 ) $criteria->addInCondition( 'category', $category ); $dataProvider = new CActiveDataProvider( 'Offer', array( 'criteria' => $criteria, ) ); $this->render( 'index', array( 'dataProvider' => $dataProvider ) ); }
May be usefull to add buttons that selects and deselects all checkBoxes
echo CHtml::button('All', array('id'=>'selectAll')) . CHtml::button('None', array('id'=>'selectNone'));
And register the following JavaScript
$('#selectAll').click(function(){ $('.categoryFilter').attr('checked','checked') category = $('.categoryFilter').serialize(); $.fn.yiiListView.update( 'ajaxListView', {data: category} ); }); $('#selectNone').click(function(){ $('.categoryFilter').removeAttr('checked') category = $('.categoryFilter').serialize(); $.fn.yiiListView.update( 'ajaxListView', {data: category} ); });
Total 9 comments
the real problem is in the 'url' propriety as vimanaboy mentioned.
adding this code will solve the problem :
and to make the request type POST you should use 'type' propriety, your code should be like :
and in the controller/your_ajax_action you should render a view that will return a CListView with the same id , this is important or your ajax call will run for once.
i hope it is clear now. and thanks to Draga for this nice wiki.
I implemented the extended case. It works well with regular GET, but the ajax does not work. I can see the ajax loading indicator, but the CListView does not update as desired. What might be the problem? How can I debug?
when the urlManager is set like this:
the CListView with AJAX filtering works as it should when i set the "url" parameter to '' :
this way it starts with a clean url - i don't know how this works, found it by chance, maybe will be useful for somebody
Looking at your email seems like the filtering form get request didn't match the url manager configuration. Strange thing !
i cutomised my url manager and its configuration just didn't work with the urls that the ajax calls generated.
i removed the url manager extra options and it works great, got to tune the configuration in config/main.php
I've tried again (with FF, IE n Chrome) and this problem still doesn't show up on my application. Maybe I've wrote something wrong or some of your logic is wrong. Show me your code or email it, I'm sending you a message you my address.
Bye
Hey Draga - thanks for your time,
here's the thing in more detail:
in my case the ajax search is filtering out the "category_id" of a "project" and there's enough records in "project" to cause the CListView to show a pagination under the list of records.
Now: when you click away on the pagination without invoking the "filter" - it's ok : after paginating back and forth you can still use the filter but:
When you use the filter first then try to paginate the filtered results and then, try to filter again: the filter doesn't work. I can see in firebug that the data is coming back from the controller action but it does not display on the screen, as if after the "pagination ajax call" some names are changing.
I didn't change anything in the code. I appreciate your work, thanks for sharing your knowledge !
Hello, I've just tested the scenario you pointed out and it still works fine to me. - I filter by ajax or GET - get new results - filtering again by AJAX or GET still works fine
The only bug I'm experiencing it's that from time to time a blank javascript alert appears, but with the late code I've developed only happened once out of tens of tests.
What do you mean more specifically by
Does the loading icon appears?
Hi Dragga,
thank you for a great tutorial! i can't solve one problem though: the code works ok but not in this scenario:
I looked for a solution here and found a lot of things i'm not yet ready to understand so just as a last hope i ask: is there a way to get around it?
thanks!!
Leave a comment
Please login to leave your comment.