Clistview Ajax Filtering With History Enable

[size="3"]I want to share a simple way to add Ajax filter in CListView with enable history support.[/size]

[size="5"]Controller[/size]

[size="2"][b]

[/b][/size][size="2"]First we will make some changes in Controller.[/size]




public function actionIndex()

{

        $model=new Test1('search');

        $model->unsetAttributes();  // clear any default values

        if(isset($_GET['Test1']))

            $model->attributes=$_GET['Test1'];


        if(isset($_GET['ajax']) && $_GET['ajax']=='ajaxListView')   {

            $this->renderPartial('index',array(

                'dataProvider'=>$model,

            ));

        } else  {

            $this->render('index',array(

                'dataProvider'=>$model,

            ));

        }    

}

[size="5"]View[/size]

[size="2"][b]

[/b][/size][size="2"]In our CListView, first we will change our data provider.[/size]




<?php $this->widget('zii.widgets.CListView', array(

    'dataProvider'=>$dataProvider->search(),

    'itemView'=>'_view',

        'enableHistory' => TRUE,

        'pagerCssClass' => "pagination",

        'id' => 'ajaxListView',

)); ?>

[size="3"][color="#222222"][font="Arial, sans-serif"]We now add a form with get method for filtering.[/font][/color]

[/size][size="3"][color="#222222"][font="Arial, sans-serif"]


<div class="form">

    <?php echo CHtml::beginForm('', 'get', array('id'=>'searchform')); ?>


    <div class="row">

        <?php echo CHtml::activeLabel($dataProvider,'id'); ?>

        <?php echo CHtml::activeTextField($dataProvider,'id') ?>

    </div>


    <div class="row">

        <?php echo CHtml::activeLabel($dataProvider,'fname'); ?>

        <?php echo CHtml::activeTextField($dataProvider,'fname') ?>


    <?php echo CHtml::endForm(); ?>

</div><!-- form -->

[/font][/color][/size][size="3"]

[font="Arial, sans-serif"][color="#222222"]Now add a Jquery script that send AJAX request when value in input filed is changed or enter button is pressed.[/color][/font]

[/size]

[size="3"]




<?php

Yii::app()->clientScript->registerScript('search',

"$('#searchform').change(function(event) {

            SearchFunc();

            return false;

});

jQuery('input').keydown(function (event) {

    if (event.keyCode && event.keyCode == '13') {

        SearchFunc();

        return false;

    } else {

        return true;

    }

});

function SearchFunc()   {

    var data = $('input').serialize();

    var url = document.URL;

    var params = $.param(data);

    url = url.substr(0, url.indexOf('?'));

    window.History.pushState(null, document.title,$.param.querystring(url, data));

}

");

?>



[/size]

[size="2"]Complete Code of our view is:[/size]


<?php

$this->breadcrumbs=array(

    'Test',

);


$this->menu=array(

    array('label'=>'Create Test1', 'url'=>array('create')),

    array('label'=>'Manage Test1', 'url'=>array('admin')),

);

?>

<h1>Test</h1>


<div class="form">

    <?php echo CHtml::beginForm('', 'get', array('id'=>'searchform')); ?>

    

    <div class="row">

        <?php echo CHtml::activeLabel($dataProvider,'id'); ?>

        <?php echo CHtml::activeTextField($dataProvider,'id') ?>

    </div>

    <div class="row">

        <?php echo CHtml::activeLabel($dataProvider,'fname'); ?>

        <?php echo CHtml::activeTextField($dataProvider,'fname') ?>

        

    <?php echo CHtml::endForm(); ?>

</div><!-- form -->


<?php $this->widget('zii.widgets.CListView', array(

    'dataProvider'=>$dataProvider->search(),

    'itemView'=>'_view',

        'enableHistory' => TRUE,

        'id' => 'ajaxListView',

)); ?>


<?php

Yii::app()->clientScript->registerScript('search',

"$('#searchform').change(function(event) {

            SearchFunc();

            return false;

});

jQuery('input').keydown(function (event) {

    if (event.keyCode && event.keyCode == '13') {

        SearchFunc();

        return false;

    } else {

        return true;

    }

});

function SearchFunc()   {

    var data = $('input').serialize();

    var url = document.URL;  

Dude, I want to thank you for this!!! It works like a charm, really helped me.

I am figuring out how to resolve some cases… I have a range date composed of two inputs… don’t know when to fire the ajax call… perhaps when the second input is completed… the same happens for a price range… perhaps adding a small submit besides the range…

Never mind… thanks again!

Hi, its me again.

I realized your solution replaces the content of the clistview (inside id= ajaxListView) with the renderPartial. The thing is that my view has more things that need to be replaced (outside ajaxListView)… is there a way to choose what to update from the server??? I don’t find it in you JavaScript…

Thanks a lot

[size="2"]Hi,

First sorry for late reply. Yii uses it’s own js to update list data, but we can use ‘afterAjaxUpdate’ to call a JavaScript function to do our other stuff.[/size]

Hi, thanks for your reply.

I found that ajaxUpdate property let me select the ID’s of the things I want to update. And of course with some afterAjaxUpdate I managed to do other things.

All the best

Sorry, its me again.

Can you tell me why this:


function SearchFunc()   {

    var data = $('input').serialize();

    var url = document.URL;

    var params = $.param(data);

    url = url.substr(0, url.indexOf('?'));

    window.History.pushState(null, document.title,$.param.querystring(url, data));

}

Fires the ajax call???

Hi,

Ajax call is fired because of state change (HTML5 property) event.


window.History.pushState(null, document.title,$.param.querystring(url, data));



change state is captured by code present in file jquery.yiilistview.js.




if(settings.enableHistory && window.History.enabled) { 	               

 $(window).bind('statechange', function() { // Note: We are using statechange instead of popstate 						

var State = window.History.getState(); // Note: We are using History.getState() instead of event.state 		               

 $.fn.yiiListView.update(id, {url: State.url}); 	               

 }); 				

}



You can also update list only by calling function $.fn.yiiListView.update("#< id of list >")

And Yii uses bbq library for handling hash/state change event. You can find it’s documentation here

Thanks!

This is BRILLIANT.

Hi, I noticed that after the ajax, my urls ends up with brackets "[" or "]" which is not recommended. Any suggestion how to avoid this?

Thanks!

Check the value in data variable in SearchFunc() function by console.log or by alert.

if brackets ("[", “]”) are there in the end of string, that’s means there is something wrong in you form.

if it’s not there, Then try to replace “$.param.querystring(url, data)” with “url+ ‘?’ + data”

Hi Akshay, thanks for your help.

In the console.log the URL looks good: %5B and %5D… I tried your suggestion but the ‘[’ still appear in the URL…

Any other idea?

Can you give an url sample?

Hi, the URL is

http://www.ritzycharters.com/yacht/index?SearchForm[area]=Caribbean&SearchForm[location]=Virgin+Islands

Once you use the form on the left (putting a number in guests for example) it changes to ‘[’.

Thanks

German

Hey buddy, I saw you site.

If you bothering about the url ending with “SearchForm[yachtMaxSize]=” this type of parameters, then don’t worry, It’s Yii’s methodology to handle forms request(GET, POST) in array format.

The brackets in url is you forms data which is converted in array format. In controller when you use $model->attributes = $_POST[‘SearchForm’], you are simply coping values in array of $_POST[‘SearchForm’] to model attributes. You can check values in $_POST[‘SearchForm’] array in you controller by using print_r.

Hi,

Many thanks for the code! :) But I have a question regaring to this. I have a problem with “[” and “]” im my url, for example: /?TblProject[id_shop]=1&TblProject[id_category]=1 so how can I fix this?