Yii 1.1: CListView AJAX filtering

29 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 17 comments

#18576 report it
ItsYii at 2014/11/20 03:45am
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

#15010 report it
buminda at 2013/09/28 01:33pm
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.

#14036 report it
playdog at 2013/07/12 04:27pm
Dear Hhello Dragga

Dear Hhello Dragga,

The solution:

var parametros = {
                    string : $('#Exitos3').val(),
                    string2 : $('#Exitos4').val()
                };
#11119 report it
Draga at 2012/12/18 09:39am
re

Sorry adlersd, it's a long time I'm not using Yii.

You may want to try some workaround or be more specific.

#11118 report it
adlersd at 2012/12/18 09:05am
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?

#10961 report it
Draga at 2012/12/06 03:19pm
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.

#10924 report it
renathy at 2012/12/03 03:13pm
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?

#9995 report it
radoo at 2012/09/27 04:04pm
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?

#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
williamhu 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.

Write new article