yii_CGridView_ajax_pagination_and_ajax_sort

本文主要內容:

1, 正常情況下 CGridView 實現 Ajax 分頁和排序的原理

2, 分頁和排序無法Ajax的情況分析

3, 自定義分頁(重寫CLinkPager)後如何實現 Ajax 分頁和排序

/***

author: php攻城師

http://blog.csdn.net/phpgcs

***/

/*********** 我是分割線 *******************************/


<?php 
$this->widget('zii.widgets.grid.CGridView', array(
    'id'=>'keyword-grid',
    'dataProvider'=>$model->search(),
    'cssFile'=>false,
    'template'=>'{items} <div class="page_area">{pager} {summary}</div>',
    'pager'=>array('cssFile'=>false),
    'ajaxUpdate'=>true,
    'columns'=>array(
        array(
            'name'=>'leader_name',
            'value'=>'$data->event',
            'header'=>'關鍵詞名稱',
            'headerHtmlOptions'=>array('width'=>'130px'),
        ), .... ....
以上代碼實現一個常規的 CGridView , 除了 pager 用了自定義的樣式。。


而在頁面的源代碼中,我來找出相關的部分:


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

<script type="text/javascript" src="/chuanmei/assets/fb90bba/gridview/jquery.yiigridview.js"></script>
<script type="text/javascript">
/*<![CDATA[*/
jQuery(function($) {
jQuery('#keyword-grid a.delete').live('click',function() {
	if(!confirm('確定要刪除這條數據嗎?')) return false;
	var th=this;
	var afterDelete=function(){};
	$.fn.yiiGridView.update('keyword-grid', {
		type:'POST',
		url:$(this).attr('href'),
		success:function(data) {
			$.fn.yiiGridView.update('keyword-grid');
			afterDelete(th,true,data);
		},
		error:function(XHR) {
			return afterDelete(th,false,XHR);
		}
	});
	return false;
});
jQuery('#keyword-grid').yiiGridView({'ajaxUpdate':['1','keyword-grid'],'ajaxVar':'ajax','pagerClass':'pager','loadingClass':'grid-view-loading','filterClass':'filters','tableClass':'items','selectableRows':1,'pageVar':'keyword_page'});
});
/*]]>*/
</script>


其中會發現 yii 自動加載了 jquery.ba-bbq.js  &&  jquery.yiigridview.js ,以及2段 代碼

其中一段是用來實現  刪除 一行數據時 彈出提示框 讓用戶 確認是否刪除 功能 的;

一段是最核心關鍵的 用於 ajax update grid 的, 也正是這部分 代碼 實現了 ajax 的翻頁 和 排序


/*********** 我是分割線 *******************************/


如果發現 點擊了 分頁 或者 排序 後,不是ajax 方式的(也就是你可以 在 地址欄 中 看到 每次 請求的常常的 url )

一個要檢查的地方:

ajaxUpdate=>'', 這個參數

updateSelector=>'', 這個參數


/*********** 我是分割線 *******************************/


一般情況下,CLinkPager都無法滿足我們的需求,要重寫;

而重寫我這裏提供3種方式:

1, 禁用 CGridView自己的Pager ,在 CGridView 之外 自己寫

2, 禁用 CGridView自己的Pager ,重寫 CGridView 文件, 將 自己的pager 寫在     public function renderItems() 中

3, 配置 CGridView 的 pager 參數。


如下是默認的 CLinkPager 的樣子

翻頁: 


現在我們想要如下的Pager 效果

第 31 - 40 條, 共 14546 條  




/***

author: php攻城師

http://blog.csdn.net/phpgcs

***/


先看第1種重寫方案:


重寫 CLinkpager 如下:

        $this->widget('CLinkPager', array(
            'header'=>'第 '.($paginationTop->getCurrentPage()*$paginationTop->getPageSize()+1).
            ' - '.($paginationTop->getCurrentPage()*$paginationTop->getPageSize()+$paginationTop->getPageSize()).
            ' 條, 共 '.$paginationTop->getItemCount().' 條  ',
            'pages' => $paginationTop,
            'itemCount'=>$totalItemFoundCount,
            'prevPageLabel' => '上一頁',
            'cssFile'=>false,
            'nextPageLabel' => '下一頁',
            'footer'=>'  ',
        )); 

其中的 pagination 在 controller 中生成

        $paginationTop = new CPagination($totalItemFoundCount);
        $paginationTop->pageSize= $pageSize;

然後把重寫的 CLinkPager 放在  CGridView 前面即可。

運行後發現一個Bug ,就是 分頁 不是 Ajax 的。

不是Ajax的不要緊, 關鍵是 分頁和排序不能結合使用了。

原因很簡單, 分頁不是ajax 的,而排序是ajax 的, 兩個 請求發出後 url 不在一個地方, 那麼分頁參數和 排序參數就 不再一地方, 當然無法結合使用。

解決方案: 統一起來。

要麼統一爲url排序&分頁, 要麼統一爲ajax排序&分頁。

url的簡單, 設置 ajaxUpdate=>false,

ajax的也簡單, 只要理解了本文第一部份說的 ajax 排序的原理,

之所以不能夠 ajax 分頁, 是因爲我們的分頁是 重寫了, 而且還放在了CGridView 之外, 這樣如何讓 

jQuery('#keyword-grid').yiiGridView({'ajaxUpdate':['1','keyword-grid'],'ajaxVar':'ajax','pagerClass':'pager','loadingClass':'grid-view-loading','filterClass':'filters','tableClass':'items','selectableRows':1,'pageVar':'keyword_page'});
 

ajaxUpdate的時候 還去照顧到你寫在外面的 CLinkPager 呢?

配置2個參數:

                    'ajaxUpdate'=>'datalist-grid, yw0',
                    'updateSelector'=>'.pager a, thead th a',


本來 ajaxUpdate 的作用範圍 只是  datalist-gird , 現在我們告訴他 還要 作用在我們重寫在grid 外面的 分頁 ul  ,其id 是 yw0.

updateSelector 指定了 觸發 ajaxUpdate 這個動作的html元素, 也是要保證 包含了 分頁的鏈接和排序的鏈接 , 否則也是無法成功 ajax 排序/分頁。


再看第2種重寫方案:


上面第一種方案 太複雜了把, 既然問題的核心關鍵是 沒有把自定義的 ClinkPager 放在 CGridView 中, 那我們就重寫 CGridView將其放進去唄。

對,確實是可行的。


<?php
Yii::import('zii.widgets.grid.CGridView');

class EbuCGridView extends CGridView
{
    /**     
     * Renders the data items for the grid view.
     */     
    public function renderItems()
    {   
        if($this->dataProvider->getItemCount()>0 || $this->showTableOnEmpty)
        {   
            $this->renderCustomerPager();
            echo "<table class=\"{$this->itemsCssClass}\">\n";
            $this->renderTableHeader();
            ob_start();
            $this->renderTableBody();
            $body=ob_get_clean();
            $this->renderTableFooter();
            echo $body; // TFOOT must appear before TBODY according to the standard.
            echo "</table>";
            $this->renderCustomerPager();
        }       
        else        
            $this->renderEmptyText();
    }                   

    public $paginationTop;
    public $totalItemCount;
    public $totalItemFoundCount;
    public function renderCustomerPager()
    {                   
        $paginationTop = $this->paginationTop;
        $totalItemCount = $this->totalItemCount;
        $totalItemFoundCount = $this->totalItemFoundCount;
        echo '<div class="page_area" style="text-align:right;">';
        echo '<div class="pager">';
        $this->widget('CLinkPager', array(
            'header'=>'第 '.($paginationTop->getCurrentPage()*$paginationTop->getPageSize()+1).
            ' - '.($paginationTop->getCurrentPage()*$paginationTop->getPageSize()+$paginationTop->getPageSize()).
            ' 條, 共 '.$paginationTop->getItemCount().' 條  ',
            'pages' => $paginationTop,
            'itemCount'=>$totalItemFoundCount,
            'prevPageLabel' => '上一頁',
            'cssFile'=>false,
            'nextPageLabel' => '下一頁',
            'footer'=>'  ',
        ));                     
....


第3種方案:


前2種方案,說實話,都太麻煩了,破壞了yii 自身的機制, 又在其上彌補了半天。。


最好的方案 ,還是 配置 CGridView 的 'pager' ,來實現我們要更復雜的CLinkPager的目標。


但是,有些時候還真必須用第 1、2種方案;

比如我應用的情況是:

用 Coreseek 全文索引 查詢出 數據 的id ,再 用 id 來到數據庫中找出數據,形成 CActiveDataProvider ,最後用 CGridView來展示。


我這裏的 CDbCriteria 如下

        $criteria = new CDbCriteria;
        $criteria->join  = 'LEFT JOIN site2 AS si** ON t.**=**.domain_hash';
        $criteria->addInCondition('t.id', $IDARRAY);
        $criteria->select = array("t.id", "t.content", "t.pubtime", "t.url", "t.reply_num", "t.retweet_num", "site_config.site_name");
        $criteria->order = 'FIND_IN_SET(t.id, "'.join(",", $IDARRAY).'")';

其中 變量 IDARRAY 正是 coreseek 得到的 一個 id 組成的數組

如果按照 普通的


        $dataProvider = new CActiveDataProvider('TData', array(
            'criteria'=>$criteria,
            'pagination'=>array(
                'pageSize'=>10,
            ),   
        ));  


是不滿足我的需求的。

因爲我的分頁和排序都是在 coreseek 中完成的, 這裏用 CActiveDataProvider 只是提供了當前頁(比如每一頁10條記錄)的10條記錄。


end。

有更好的建議和意見,歡迎提出共同學習。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章