Error With Cgridview 'filter' Property, Error Code ::has No Method 'querystring'

Hi, I’m having problem with the filter functionality in CGridview. The filter box doesn’t works at all. Nothing happens when i type something, and hit enter.

Here is the view code selectproducts.php::





<div id="shortcodes" class="page">

    <div class="container">


        <!-- Title Page -->

        <div class="row">

            <div class="span12">

                <div class="title-page">

                    <h2 class="title">Available Products</h2>


                </div>

            </div>

        </div>

        <!-- End Title Page -->





        <!-- Start Product Section -->

        <div class="row">




            <?php

            


            $this->widget('bootstrap.widgets.TbGridView', array(

                'id' => 'products-grid',

                'dataProvider' => $dataProvider,

                'filter' => $dataProvider->model,

                'ajaxUpdate' => TRUE,

                'pager' => array(

                    'header' => '',

                    'cssFile' => false,

                    'maxButtonCount' => 25,

                    'selectedPageCssClass' => 'active',

                    'hiddenPageCssClass' => 'disabled',

                    'firstPageCssClass' => 'previous',

                    'lastPageCssClass' => 'next',

                    'firstPageLabel' => '<<',

                    'lastPageLabel' => '>>',

                    'prevPageLabel' => '<',

                    'nextPageLabel' => '>',

                ),

                'columns' => array(

                    'id',

                    array(

                      'name' => 'name',

                      

                    ),

                    'category',

                    'brand',

                    'weight_unit',

                    'price_unit',

                    'flavors',

                    array(

                        'name' => 'providers',

                        'value' => function($data) {

                            return '<div class="provider-label label label-info"><a href="http://www.'.$data->providers. '">'. $data->providers .'</a></div>';

                        },

                        'type' => 'raw',

                    ),

                ),

            ));

            ?>


        </div>

        <!-- End Product Section -->




    </div>

</div>






Here is the relevant action in ProductsController that is rendering this view. The $dataprovider variable in the view is a CActiveDataProvider object which holds the result of a conditional query.





public function actionDropdown() {


        if (isset($_GET["Dropdown"])) {

            $dropdownData = $_GET["Dropdown"];

            $this->category = $dropdownData["category"];

            $this->price = $dropdownData["price"];

        }

        // separate the price text into min and max value

        $priceText = explode(" - ", $this->price);  

        

        

        

        $criteria = new CDbCriteria;

        $criteria->compare('category', $this->category, true);

        

        $criteria->addBetweenCondition('price', substr($priceText[0], 1), substr($priceText[1], 1), 'AND');

        

        $dataProvider = new CActiveDataProvider('Products', array(

            'criteria' => $criteria,

            'pagination' => array(

                'pageSize' => 20,

            ),

            'sort' => array(

                'defaultOrder' => 'price_unit, name',

            ),

        ));


        

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

            'dataProvider' => $dataProvider,

            

        ));

    }






And here is the Products model search() function ::





public function search()

	{

		// @todo Please modify the following code to remove attributes that should not be searched.


		$criteria=new CDbCriteria;


		$criteria->compare('id',$this->id);

		$criteria->compare('name',$this->name,true);

		$criteria->compare('category',$this->category,true);

		$criteria->compare('brand',$this->brand,true);

		$criteria->compare('weight',$this->weight,true);

		$criteria->compare('weight_unit',$this->weight_unit,true);

		$criteria->compare('price',$this->price,true);

		$criteria->compare('price_unit',$this->price_unit,true);

		$criteria->compare('flavors',$this->flavors,true);

		$criteria->compare('providers',$this->providers,true);


		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria,

		));

	}




Now, when i hit enter in the filter box, i’m getting this error, which is logged in firebug





TypeError: $.param.querystring is not a function

[Break On This Error] 	


options.url = $.param.querystring(options.url, options.data);


In file jquery.yiigridview.js



Does anyone knows what is causing this error. I just can’t figure out what is causing this. And i also don’t know what modification should i do in jquery.yiigridview.js to fix this error.

Thanks in advance.

Maxx

I recommend to generate controller and views using Gii and check the “admin” action… I don’t even see where is in your code a call to search() method :)

Yes i have already generated the whole project using Gii. The search() function is the one created by Gii in the model. I thought it might be useful to fix the errors. In fact every models, controllers, views in my project are the ones generated by Gii.

Also even the admin panel where you can edit, delete, or view a record, is giving me the same error whenever i type something in the filter box and hit enter, i.e.




   

   TypeError: $.param.querystring is not a function

[Break On This Error] 	


options.url = $.param.querystring(options.url, options.data);


In file jquery.yiigridview.js




Even more this error is happening for all the views. I just don’t know what should i do about it.

I tried to move the CActiveDataProvider logic in the model in hopes that using $model->search() will fix the error. But alas! i’m getting the same errors.

Here are the codes

Controller:::





public function actionDropdown() {


    $dataProvider = new Products;


    if (isset($_GET["Dropdown"])) {

        $dropdownData = $_GET["Dropdown"];

        $this->category = $dropdownData["category"];

        $this->price = $dropdownData["price"];

    }




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

        'dataProvider' => $dataProvider,

        'category' => $this->category,

        'price' => $this->price,

        //'num' => $this->numResults,

    ));

}







Here is the model ::





public function searchDropdown($category, $price) {


    $this->priceText = explode(" - ", $price);  


    $this->criteria = new CDbCriteria;

    $this->criteria->compare('category', $category, true);


    $this->criteria->addBetweenCondition('price', substr($this->priceText[0], 1), substr($this->priceText[1], 1), 'AND');


    return new CActiveDataProvider('Products', array(

        'criteria' => $this->criteria,

        'pagination' => array(

            'pageSize' => 25,

        ),

        'sort' => array(

            'defaultOrder' => 'price_unit, name',

        ),

    ));





}




And here is the view ::





<div id="shortcodes" class="page">

<div class="container">


    <!-- Title Page -->

    <div class="row">

        <div class="span12">

            <div class="title-page">

                <h2 class="title">Available Products</h2>


            </div>

        </div>

    </div>

    <!-- End Title Page -->





    <!-- Start Product Section -->

    <div class="row">




        <?php




        $this->widget('bootstrap.widgets.TbGridView', array(

            'id' => 'products-grid',

            'dataProvider' => $dataProvider->searchDropdown($category, $price),

            'filter' => $dataProvider,

            'ajaxUpdate' => TRUE,

            'pager' => array(

                'header' => '',

                'cssFile' => false,

                'maxButtonCount' => 25,

                'selectedPageCssClass' => 'active',

                'hiddenPageCssClass' => 'disabled',

                'firstPageCssClass' => 'previous',

                'lastPageCssClass' => 'next',

                'firstPageLabel' => '<<',

                'lastPageLabel' => '>>',

                'prevPageLabel' => '<',

                'nextPageLabel' => '>',

            ),

            'columns' => array(

                array(

                    'name' => 'id',

                    'type' => 'raw',

                ),

                array(

                  'name' => 'name',




                ),

                'category',

                'brand',

                'weight_unit',

                'price_unit',

                'flavors',

                array(

                    'name' => 'providers',

                    'value' => function($data) {

                        return '<div class="provider-label label label-info"><a href="http://www.'.$data->providers. '">'. $data->providers .'</a></div>';

                    },

                    'type' => 'raw',

                ),

            ),

        ));

        ?>


    </div>

    <!-- End Product Section -->




</div>




Still its not working. i.e. Nothing happens when i type something in the filter box and hit enter. The same error comes up ::

In Firebug





TypeError: $.param.querystring is not a function

[Break On This Error]   


options.url = $.param.querystring(options.url, options.data);


In file jquery.yiigridview.js




And in Chrome i get a slightly more descriptive error message.





Uncaught TypeError: Object function (e,n){var r,i=[],o=function(e,t)


{t=x.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=x.ajaxSettings&&


x.ajaxSettings.traditional),x.isArray(e)||e.jquery&&!x.isPlainObject(e))x.each(e,function(){o(this.name,this.value)});

else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")} 


has no method 'querystring' 


jquery.yiigridview.js:310




I just can’t figure out what to do. What modification should i do to the js file to fix it?

So does anyone know whats causing this error. Its driving me crazy all through the day.

Well, there is too much difference between your code and code generated by gii… I can post an example that works perfectly for me:

in grid view:




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

    'filter'=>$model,



in action:




$model = new ModelClass('search');

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

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

    $model->setAttributes($_GET['ModelClass']);



in model:




public function rules()

{

    return array(

        ...

        array('id, name, ...', 'safe', 'on'=>'search'),

    );

}


public function search($num = 30)

{

    $criteria = new CDbCriteria;

    $criteria->compare('name', $this->name, true);

    // ...


    return new CActiveDataProvider($this, array(

        'criteria'=>$criteria,

        'pagination'=>array(

            'pageSize'=>$num,

        ),

    ));

}



I hope it helps :unsure:

Check the jquery ba-bbq plugin (bbq package) - it is loaded or not - I think it’s missing.

The CGridView register here: framework/zii/widgets/grid/CGridView.php#L471

or maybe an extra jquery script is overwrite the plugin, e.g:




<script type="text/javascript" src="/assets/.../jquery.js"></script>

<script type="text/javascript" src="/assets/.../jquery.ba-bbq.js"></script>

...

<script type="text/javascript" src="another/jquery.js"></script>

...



Thanks for your response. But like i mentioned above i’m getting the same error right after the default code is generated by Gii, before making any changes to the existing code. So i think it may be some JS related problem.

Yes that got rid of the error. But the filter is not working yet. The ajax load icon is showing in the left upper hand of the table for less than a second and then nothing is happening after it.

Here is what i added ::





<script src="<?php echo Yii::app()->assetManager->baseUrl;?>/28e7347b/jquery.ba-bbq.js"></script>



How will i make the filter work ? Do i need to initialize it from jQuery.

Also i added all of the scripts in the assets folder because i thought they might be overridden by the site specific custom js that i added before.

Here is how it looks now ::





 <script src="<?php echo Yii::app()->assetManager->baseUrl; ?>/28e7347b/jquery.ba-bbq.js"></script>

        <script src="<?php echo Yii::app()->assetManager->baseUrl; ?>/28e7347b/jquery.jquery.ajaxqueue.js"></script>

        <script src="<?php echo Yii::app()->assetManager->baseUrl; ?>/28e7347b/jquery.autocomplete.js"></script>

        <script src="<?php echo Yii::app()->assetManager->baseUrl; ?>/28e7347b/jquery.bgiframe.js"></script>

        <script src="<?php echo Yii::app()->assetManager->baseUrl; ?>/28e7347b/jquery.maskedinput.js"></script>

        <script src="<?php echo Yii::app()->assetManager->baseUrl; ?>/28e7347b/jquery.metadata.js"></script>

        <script src="<?php echo Yii::app()->assetManager->baseUrl; ?>/28e7347b/jquery.treeview.js"></script>

        <script src="<?php echo Yii::app()->assetManager->baseUrl; ?>/28e7347b/jquery.treeview.async.js"></script>

        <script src="<?php echo Yii::app()->assetManager->baseUrl; ?>/28e7347b/jquery.treeview.edit.js"></script>

        <script src="<?php echo Yii::app()->assetManager->baseUrl; ?>/28e7347b/jquery.yii.js"></script>

        <script src="<?php echo Yii::app()->assetManager->baseUrl; ?>/28e7347b/jquery.yiiactiveform.js"></script>

        <script src="<?php echo Yii::app()->assetManager->baseUrl; ?>/28e7347b/jquery.yiitab.js"></script>

        <script src="<?php echo Yii::app()->assetManager->baseUrl; ?>/28e7347b/punycode.js"></script>






One good news of this is that the ajax sorting is now working properly. By ajax sorting im refering the sorting that takes place when the header cells of the table is clicked. Previously it worked bu with a page refresh. I wanted ajaxify it, but didn’t knew how, and now after adding the scripts again at the bottom, made it work. Now the sort happens correctly without a page refresh

But i’m still stuck with the filter. Is there a way to manually call it using jquery ? If there is then i may do so, i need to get this working somehow. Its one of the vital component of the site. Without it the visitors will face severe torture because they would have to navigate through more than 30k rows just to find the product they’re looking for.

Thanks again for your help.

Also i see the correct parameter being passed after i hit enter in the filter box.

Here is what i’m seeing ::





Dropdown[category]  Chant Books

Dropdown[price] $340 - $476

Products[brand] 

Products[category]  

Products[flavors]   

Products[name]  Owl Chant Scroll

Products[price_unit]    

Products[providers] 

Products[weight_unit]   

Products_page   1

ajax    products-grid

yt0 




Well at last the problem is solved. It turned out that i needed to add the ajaxUpdate and the ajaxURL property of the Gridview widget. And make another action for the ajax filter.




'ajaxUpdate' => 'products-grid'

                'ajaxUrl' => Yii::app()->createUrl('products/UpdateGrid'),




.

Anyways here are the code, which works now.

the action methods in the products controller ::





 public function actionDropdown() {

        

        /*

         * create the session to store the dropdown variables

         * 

         * 

         */

        

        $this->session = new CHttpSession;

        $this->session->open();

        

        $dataProvider = new Products;

        $products = new Products('search');

        $products->unsetAttributes();


        if (isset($_GET["Dropdown"])) {

            $dropdownData = $_GET["Dropdown"];

            $this->category = $dropdownData["category"];

            $this->price = $dropdownData["price"];

            

            $this->session["category"] = $this->category;

            $this->session["price"] = $this->price;

        }

        

        if (isset($_GET["Products"])) {

            $products->attributes = $_GET["Products"];

        }

        

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

            'dataProvider' => $dataProvider,

            'products' => $products,

            'category' => $this->category,

            'price' => $this->price,

                //'num' => $this->numResults,

        ));

    }

    

    public function actionUpdateGrid() {

       

        $products = new Products;

       

        $products->unsetAttributes();

        

        

        if (isset($_GET["Products"])) {

            $products->attributes = $_GET["Products"];

           

        }

        

       

        

        

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

            'products' => $products,

            'category' => $this->category,

            'price' => $this->price,

            

        ));

        

    }




The Product model code::





/**

     * Retrieves a list of models based on the current search/filter conditions.

     *

     * Typical usecase:

     * - Initialize the model fields with values from filter form.

     * - Execute this method to get CActiveDataProvider instance which will filter

     * models according to data in model fields.

     * - Pass data provider to CGridView, CListView or any similar widget.

     *

     * @return CActiveDataProvider the data provider that can return the models

     * based on the search/filter conditions.

     */

    public function search() {

        // @todo Please modify the following code to remove attributes that should not be searched.


        $criteria = new CDbCriteria;


        $criteria->compare('id', $this->id);

        $criteria->compare('name', $this->name, true);

        $criteria->compare('category', $this->category, true);

        $criteria->compare('brand', $this->brand, true);

        $criteria->compare('weight', $this->weight, true);

        $criteria->compare('weight_unit', $this->weight_unit, true);

        $criteria->compare('price', $this->price, true);

        $criteria->compare('price_unit', $this->price_unit, true);

        $criteria->compare('flavors', $this->flavors, true);

        $criteria->compare('providers', $this->providers, true);







        return new CActiveDataProvider($this, array(

            'criteria' => $criteria,

        ));

    }


    /**

     * Returns the static model of the specified AR class.

     * Please note that you should have this exact method in all your CActiveRecord descendants!

     * @param string $className active record class name.

     * @return Products the static model class

     */

    public static function model($className = __CLASS__) {

        return parent::model($className);

    }


    /*

     * Dropdown search

     * 

     * 

     */


    public function searchDropdown($category, $price) {


        $this->priceText = explode(" - ", $price);


        $this->criteria = new CDbCriteria;

        $this->criteria->compare('category', $category, true);


        $this->criteria->addBetweenCondition('price', substr($this->priceText[0], 1), substr($this->priceText[1], 1), 'AND');


        return new CActiveDataProvider('Products', array(

            'criteria' => $this->criteria,

            'pagination' => array(

                'pageSize' => 25,

            ),

            'sort' => array(

                'defaultOrder' => 'price_unit, name',

            ),

        ));

    }


    public function searchGrid() {

        

        $session = new CHttpSession;

        $session->open();

        

        

        $category = $session["category"];

        

        

        $this->criteria = new CDbCriteria;

        

        $this->priceText = explode(" - ", $session["price"]);

        $this->criteria->compare('category', $category, true);


        $this->criteria->addBetweenCondition('price', substr($this->priceText[0], 1), substr($this->priceText[1], 1), 'AND');

        

        /*

         * 

         * compare the names to see if the flavor or weight is present

         * 

         */

         

        $this->criteria->compare('name', $this->flavors, TRUE);

        $this->criteria->compare('name', $this->weight, TRUE);

        

        $this->criteria->compare('id', $this->id);

        $this->criteria->compare('name', $this->name, true);

        $this->criteria->compare('category', $this->category, true);

        $this->criteria->compare('brand', $this->brand, true);

        $this->criteria->compare('weight', $this->weight, true);

        $this->criteria->compare('weight_unit', $this->weight_unit, true);

        $this->criteria->compare('price', $this->price, true);

        $this->criteria->compare('price_unit', $this->price_unit, true);

        $this->criteria->compare('flavors', $this->flavors, true);

        $this->criteria->compare('providers', $this->providers, true);

        

        

        return new CActiveDataProvider($this, array(

            'criteria' => $this->criteria,

            'pagination' => array(

                'pageSize' => 25,

            ),

            'sort' => array(

                'defaultOrder' => 'price_unit, name',

            ),

        ));

        

    }




And the views::

view name::- selectproducts.php





<div id="shortcodes" class="page">

    <div class="container">


        <!-- Title Page -->

        <div class="row">

            <div class="span12">

                <div class="title-page">

                    <h2 class="title">Available Products</h2>


                </div>

            </div>

        </div>

        <!-- End Title Page -->





        <!-- Start Product Section -->

        <div class="row">




            <?php

            $this->widget('bootstrap.widgets.TbGridView', array(

                'id' => 'products-grid',

                'dataProvider' => $dataProvider->searchDropdown($category, $price),

                'filter' => $products,

                'ajaxUpdate' => 'products-grid',

                'ajaxUrl' => Yii::app()->createUrl('products/UpdateGrid'),

                'pager' => array(

                    'header' => '',

                    'cssFile' => false,

                    'maxButtonCount' => 25,

                    'selectedPageCssClass' => 'active',

                    'hiddenPageCssClass' => 'disabled',

                    'firstPageCssClass' => 'previous',

                    'lastPageCssClass' => 'next',

                    'firstPageLabel' => '<<',

                    'lastPageLabel' => '>>',

                    'prevPageLabel' => '<',

                    'nextPageLabel' => '>',

                ),

                'columns' => array(

                    array(

                        'name' => 'name',

                        'value' => function($data) {

                            return '<div class="custom-badge">' . $data->name . '</div>';

                        },

                        'type' => 'raw',

                    ),

                    array(

                        'name' => 'category',

                        'value' => function($data) {

                            return '<div class="grid-glow">' . $data->category . '</div>';

                        },

                        'type' => 'raw',

                    ),

                    array(

                        'name' => 'brand',

                        'value' => function($data) {

                            return '<div class="grid-glow">' . $data->brand . '</div>';

                        },

                        'type' => 'raw',

                    ),

                    array(

                        'name' => 'weight_unit',

                        'value' => function($data) {

                            return '<div class="grid-glow">' . $data->weight_unit . '</div>';

                        },

                        'type' => 'raw',

                    ),

                     array(

                        'name' => 'price_unit',

                        'value' => function($data) {

                            return '<div class="grid-price-glow">' . $data->price_unit . '</div>';

                        },

                        'type' => 'raw',

                    ),

                    array(

                        'name' => 'flavors',

                        'value' => function($data) {

                            return '<div class="grid-glow">' . $data->flavors . '</div>';

                        },

                        'type' => 'raw',

                    ),

                    array(

                        'name' => 'providers',

                        'value' => function($data) {

                            return '<div class="provider-label label label-info"><a href="http://www.' . $data->providers . '">' . $data->providers . '</a></div>';

                        },

                        'type' => 'raw',

                    ),

                ),

            ));

            ?>


        </div>

        <!-- End Product Section -->




    </div>

</div>






view name::- _selectproducts.php





<?php

           

            $this->widget('bootstrap.widgets.TbGridView', array(

                'id' => 'products-grid',

                'dataProvider' => $products->searchGrid($category, $price),

                'filter' => $products,

                'ajaxUpdate' => TRUE,

                'pager' => array(

                    'header' => '',

                    'cssFile' => false,

                    'maxButtonCount' => 25,

                    'selectedPageCssClass' => 'active',

                    'hiddenPageCssClass' => 'disabled',

                    'firstPageCssClass' => 'previous',

                    'lastPageCssClass' => 'next',

                    'firstPageLabel' => '<<',

                    'lastPageLabel' => '>>',

                    'prevPageLabel' => '<',

                    'nextPageLabel' => '>',

                ),

                'columns' => array(

                    array(

                        'name' => 'name',

                        'value' => function($data) {

                            return '<div class="custom-badge">' . $data->name . '</div>';

                        },

                        'type' => 'raw',

                    ),

                    array(

                        'name' => 'category',

                        'value' => function($data) {

                            return '<div class="grid-glow">' . $data->category . '</div>';

                        },

                        'type' => 'raw',

                    ),

                    array(

                        'name' => 'brand',

                        'value' => function($data) {

                            return '<div class="grid-glow">' . $data->brand . '</div>';

                        },

                        'type' => 'raw',

                    ),

                    array(

                        'name' => 'weight_unit',

                        'value' => function($data) {

                            return '<div class="grid-glow">' . $data->weight_unit . '</div>';

                        },

                        'type' => 'raw',

                    ),

                     array(

                        'name' => 'price_unit',

                        'value' => function($data) {

                            return '<div class="grid-price-glow">' . $data->price_unit . '</div>';

                        },

                        'type' => 'raw',

                    ),

                    array(

                        'name' => 'flavors',

                        'value' => function($data) {

                            return '<div class="grid-glow">' . $data->flavors . '</div>';

                        },

                        'type' => 'raw',

                    ),

                    array(

                        'name' => 'providers',

                        'value' => function($data) {

                            return '<div class="provider-label label label-info"><a href="http://www.' . $data->providers . '">' . $data->providers . '</a></div>';

                        },

                        'type' => 'raw',

                    ),

                ),

            ));

            ?>




Well as you see the ajax filter needed a new action method which will render a partial view containing just the result grid.

I hope it helps someone who is stuck with the same error.

Thanks,

Maxx