You are viewing revision #4 of this wiki article.
This is the latest version of this article.
You may want to see the changes made in this revision.
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
String filter ¶
View ¶
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);
});"
);
Controller action ¶
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 ) );
}
Extended use ¶
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
View ¶
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
[javascript]
$('.categoryFilter').change(function(){
category = $('.categoryFilter').serialize();
$.fn.yiiListView.update(
'ajaxListView',
{data: category}
);
});
Controller ¶
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 ~~~ [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}
);
});
Problem with filtering after changing the page number via ajax
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!!
tested
Hello,
I've just tested the scenario you pointed out and it still works fine to me.
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
> try to filter out again - doesn't work
Does the loading icon appears?
when the Clistview pagination interferes, it stops working
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 !
k
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
sorry my big fault
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
k
Looking at your email seems like the filtering form get request didn't match the url manager configuration. Strange thing !
to make it work with urlManager
when the urlManager is set like this:
'urlManager'=>array( 'class'=>'application.components.MyCUrlManager', 'urlFormat'=>'path', 'showScriptName'=>false, ),
the CListView with AJAX filtering works as it should when i set the "url" parameter to '' :
$.fn.yiiListView.update( 'ajaxListView', { url: '', data: ajaxRequest } )
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
Ajax does not work
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?
Tips to fix the problem with urlManager
the real problem is in the 'url' propriety as vimanaboy mentioned.
adding this code will solve the problem :
'ajaxListView', { url: '" . CController::createUrl('controller/your_ajax_action') . "', data: ajaxRequest }
and to make the request type POST you should use 'type' propriety, your code should be like :
'ajaxListView', { type: 'POST', url: '" . CController::createUrl('controller/your_ajax_action') . "', data: ajaxRequest }
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.
great tutorial. pls help further!
So I got everything working great in a similar setup.
Now, for each view I am trying to add (in the templated _view.php file) an ajax link to call a function to operate with that item when I click the button.
So I am doing this:
<?php echo CHtml::ajaxLink( 'Vote for this!', array( 'product/voteUp', ), array( 'type'=>'POST', 'data'=> array('divid'=> $data->id), ), )
What I am doing here is call the VoteUp function in the Product controller and send the divid as variable with the id of the respective item.
Everything works great UNTIL i go to any subpage of the search result. For any subpage, the ajax buttons are still sending the id's of the first page, instead of the id's that correspond to the items displayed in the subpage.
Any idea why and how to fix this?
Return url
Hi!
1) I have done my Product list filter by Category (checkboxes) using your suggestions.
Now I have the following problem: all filtered data are products, each product has a link "details for this product". When you click on given link, you can see details for given product.
I need "Return URL" on this product detail page so that user will be returned to the previously filtered results.
2) I have also another question - is this solution SEO friendly? For my small understanding of SEO, bot could not crawl categories filter. Or this is not the case and my question doesn't make sense?
Hello renathy
I think you have to add some code to filter with the common get system (like with color=red at the end of the url) so that if you enter into a product page you can generate an url to go back to exactly the same results.
Im sorry i cannot help you with your second question for I aint expert.
two arrays
Hhello Dragga,
is it possible to get two serializables checkbox's groups working?
I was trying
[ ... ]
{data: {'group':group, 'category':category}}
[...]
but it breaks the array.
Do you have any hint?
re
Sorry adlersd, it's a long time I'm not using Yii.
You may want to try some workaround or be more specific.
Dear Hhello Dragga
Dear Hhello Dragga,
The solution:
var parametros = { string : $('#Exitos3').val(), string2 : $('#Exitos4').val() };
Adding more criteria
Thanks for sharing this.
'criteria' => array(
'with' => xxxx, 'condition' => xxx, 'group' => xxx, 'together' => xxx, 'order' => xx, 'condition' => xxx,) can be added like this.
Deselect last element
Hi,
If I deselect the last chechbox it still appears, I want to display no results if nothing is selected.
How can I do so?
Thanks
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.