CListView AJAX filtering

15 followers

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

$('.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

$('#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

#5296 report it
muaid at 2011/10/02 06:53am
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.

#5270 report it
yichuanhu at 2011/09/28 07:32pm
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?

#3990 report it
vimanaboy at 2011/05/25 08:20am
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

#3985 report it
Draga at 2011/05/25 03:41am
k

Looking at your email seems like the filtering form get request didn't match the url manager configuration. Strange thing !

#3981 report it
vimanaboy at 2011/05/24 07:34pm
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

#3963 report it
Draga at 2011/05/24 03:16am
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

#3958 report it
vimanaboy at 2011/05/23 07:18pm
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 !

#3936 report it
Draga at 2011/05/23 03:56am
tested

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

try to filter out again - doesn't work

Does the loading icon appears?

#3929 report it
vimanaboy at 2011/05/22 10:05pm
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:

  • first, filter out the results
  • end up on a ajax-refreshed page that contains a pagination
  • click on a pagination link
  • try to filter out again - doesn't work

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 to leave your comment.