2012年3月10日 星期六

ASP.NET MVC 3 分頁 - 使用jQuery.Templates + jQuery Pagination Plugin


上一篇「ASP.NET MVC 3 資料套用範本 - 使用jQuery.Templates」介紹了如何在ASP.NET MVC 3中使用jQuery.Templates,

而本部落格也有一系列的分頁文章「資料分頁」,所以這一次就來介紹如何在ASP.NET MVC 3中使用jQuery.Templates完成分頁的功能,

其實要取得分頁的資料來源是比較容易的,只要在後端處理好每次要取得分頁的資料量與資料內就可以,

之前一系列「資料分頁」的文章中,我有建立了一個有關生成Pager的HtmlHelper,

而每一次的分頁不管是GET方式還是POST,從前端傳送需求到後端,後端會連同Pager的內容也一併生成且送回到前端顯示,

因為我們使用jQuery.Templates所使用的資料是JSON,只會是包含分頁資料本身,也就是說頁面上的Pager我們要在前端處理,

本篇文章將會在前端使用「jQuery Pagination Plugin」來做為前端的Pager,以作為我們前端分頁操作介面的解決方案。


jQuery Pagination Plugin

http://blog.ajaxmasters.com/jquery-pagination-plugin/

Demo:http://tutorials.ajaxmasters.com/pagination-demo/

image

其實jQuery Plugins中有關分頁的套件相當地多,有的功能與介面UI甚至比這一個好很多,那為何要介紹這個來使用呢?

一、介面與原本我們所使用的MvcPaging相似

二、在頁面上的使用與整合還算簡單

 

這個套件的使用相當簡單,由下圖中的使用設定方式就可見一二,

image

對於要顯示分頁pager的容器設定pagination方法,方法的第一個參數是全部資料的數目,不是分頁資料數,

而第二個參數為一個option的內容,像這個範例的兩個option參數有「item_per_page」「callback」,

item_per_page,這個就是我們做分頁所會用到的page_size,每個分頁的資料數。

callback,這個就是要指定一個點選分頁後所要執行的callback方法,這個callback方法就是執行取得分頁資料以及顯示分頁資料內容。

 

來看看 jquery.pagination plugin 所預設的option參數內容:

    opts = jQuery.extend({
        items_per_page: 10,
        num_display_entries: 10,
        current_page: 0,
        num_edge_entries: 0,
        link_to: "#",
        prev_text: "Prev",
        next_text: "Next",
        ellipse_text: "...",
        prev_show_always: true,
        next_show_always: true,
        callback: function () { return false; }
    }, opts || {});

這些預設值都可以讓我們做設定的修改,在 pagination()方法的option參數做指定就可以,以下說明幾個會需要修改的參數,

items_per_page:分頁數

num_display_entries:pager最多顯示的分頁數量

prev_text:顯示上一頁的文字

next_text:顯示下一頁的文字

prev_show_always:是否總是顯示上一頁

next_show_always:是否總是顯示下一頁

 

在進入主題之前,就先來看看我們所要完成的功能與操作是什麼樣子!

ASP.NET MVC 3 + jQuery.Templates + jQuery Pagination Plugin 完成分頁功能

 



Controller / Action 方法

這裡我們會建立三個Action方法,第一個是主要顯示頁面的Action方法,

public ActionResult PageMethod()
{
    ViewData["CategoryDDL"] = categoryService.GenerateCategoryDDL(null);
    return View();
}

 

第二個則是要取得選定分類下的產品總數,這是要給jquery.pagination方法的第一個參數來使用,

這個只會在選定分類並顯示該分類第一頁的資料時才會去執行,之後的分頁都不會執行這個Action,

[HttpPost]
public JsonResult ProductCount(string categoryId)
{
    Dictionary<string, object> jo = new Dictionary<string, object>();
 
    if (string.IsNullOrWhiteSpace(categoryId))
    {
        jo.Add("Msg", "Please Select a Category");
        return this.Json(jo);
    }
 
    int id = 0;
    bool parseResult = int.TryParse(categoryId, out id);
    if (!parseResult)
    {
        jo.Add("Msg", "Wrong Category ID");
        return this.Json(jo);
    }
 
    var result = this.productService.GetCollectionBy(id);
    jo.Add("count", result.Count());
    return this.Json(jo);
}

 

第三個Action方法則是取得指定分類以及指定分頁的分頁資料,

這一個Action方法取得分頁資料的地方是會使用到MvcPaging的ToPagedList()方法,

[HttpPost]
public JsonResult PageContent(int? page, string categoryId)
{
    Dictionary<string, string> jo = new Dictionary<string, string>();
 
    if (string.IsNullOrWhiteSpace(categoryId))
    {
        jo.Add("Msg", "Please Select a Category");
        return this.Json(jo);
    }
 
    int id = 0;
    bool parseResult = int.TryParse(categoryId, out id);
 
    if (!parseResult)
    {
        jo.Add("Msg", "Wrong Category ID");
        return this.Json(jo);
    }
 
    var result = this.productService.GetCollectionBy(id);
 
    int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
    ViewData["CurrentPage"] = currentPageIndex;
    var dataPaged = result.ToPagedList(currentPageIndex, 5);
 
    List<Dictionary<string, object>> ja = new List<Dictionary<string, object>>();
 
    foreach (var item in dataPaged)
    {
        Dictionary<string, object> product = new Dictionary<string, object>();
 
        product.Add("ProductID", item.ProductID);
        product.Add("ProductName", item.ProductName);
        product.Add("SupplierID", item.SupplierID);
        product.Add("CategoryID", item.CategoryID);
        product.Add("QuantityPerUnit", item.QuantityPerUnit);
        product.Add("UnitPrice", String.Format("{0:F}", item.UnitPrice));
        product.Add("UnitsInStock", item.UnitsInStock);
        product.Add("UnitsOnOrder", item.UnitsOnOrder);
        product.Add("ReorderLevel", item.ReorderLevel);
        product.Add("Discontinued", item.Discontinued);
 
        ja.Add(product);
    }
 
    return this.Json(ja);
}  

 

View

這邊先看View頁面中的HTML內容,JavaScript的內容稍後再看,

裡面要注意的是,有一個ID為「Panination」的DIV,這是用來顯示Pager的地方,

而Table的地方,只有設定thead的內容,而tbody的內容則會搭配jQuery.Templates來動態顯示分頁資料,

@{
    ViewBag.Title = "PageMethod";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
@section HeadContent
{
    <link href="@Url.Content("~/Content/pagination.css")" rel="stylesheet" type="text/css" />
}
<div id="TableContent" class="div_default">
    <h2>PageMethod</h2>
    <div id="formArea" style="width: 90%; margin-left: auto; margin-right: auto;">
        Category:@Html.Raw(ViewData["CategoryDDL"].ToString())
        <input type="button" id="ButtonSearch" value="List" />
    </div>
    <hr />
    <p></p>
    <div id="Information" style="display: none; width: 90%; margin-left: auto; margin-right: auto; background-color: #fffeee;">
        Category:<span id="CategoryName" style="font-weight: bold;"></span>
        The number of products:<span id="ProductNumber" style="font-weight: bold;"></span>
        <p></p>
    </div>
 
    <div id="Pagination" class="pagination" style="width: 90%; margin-left: auto; margin-right: auto;">
    </div>
    <br style="clear:both;" />
 
    <table id="table1" class="grid" style="width: 90%; margin-left:auto; margin-right:auto; background-color: #fffeee;">
        <thead>
            <tr>
                <th>
                    ProductID
                </th>
                <th>
                    ProductName
                </th>
                <th>
                    SupplierID
                </th>
                <th>
                    CategoryID
                </th>
                <th>
                    QuantityPerUnit
                </th>
                <th>
                    UnitPrice
                </th>
                <th>
                    UnitsInStock
                </th>
                <th>
                    UnitsOnOrder
                </th>
                <th>
                    ReorderLevel
                </th>
                <th>
                    Discontinued
                </th>
            </tr>
        </thead>
        <tbody>
        </tbody>
    </table>
    <p></p>
</div>

 

jQuery.Template的分頁資料顯示範本

顯示分頁資料內容所使用,搭配jQuery.Templates,當AJAX取得JSON資料後,依照JSON的欄位資料並對應到範本上所指定的顯示位置,

每個顯示位置的參數名稱都須對照JSON的資料欄位名稱。

<script id="TemplateProduct" type="text/x-jquery-tmpl">
    <tr id="tr_${ProductID}">
        <td>
            ${ProductID}
        </td>
        <td>
            ${ProductName}
        </td>
        <td>
            ${SupplierID}
        </td>
        <td>
            ${CategoryID}
        </td>
        <td>
            ${QuantityPerUnit}
        </td>
        <td>
            ${UnitPrice}
        </td>
        <td>
            ${UnitsInStock}
        </td>
        <td>
            ${UnitsOnOrder}
        </td>
        <td>
            ${ReorderLevel}
        </td>
        <td>
            ${Discontinued}
        </td>
    </tr>
</script>

 

JavaScript程式內容

開頭

一開始除了在document.ready方法去設定頁面上指定element的操作外,我們也設定了四個全域參數,

這四個全域參數依序分別是,指定分頁數、分類產品總數、分類ID、分類名稱。

在接下來的function中會使用到這四個全域參數來存放資料。

var pageSize = 5;
var totalCount = 0;
var selected_Category_ID = '';
var selected_Category_Text = '';
 
$(document).ready(function ()
{
    $('#CategoryDDL option:eq(0)').attr('selected', true);
    $('#ButtonSearch').click(function (){ ButtonSearchEventHandler() });
});

 

ButtonSearchEventHandler()

這個function是在頁面上選擇產品分類後按下「List」Button所要執行的內容,

這裡所要做的事分別為:

  • 取得分類的產品總數
  • 顯示該分類第一個分頁資料以及使用並設定jQuery.pagination,以顯示Pager
function ButtonSearchEventHandler()
{
    selected_Category_ID = $.trim($('#CategoryDDL option:selected').val());
    selected_Category_Text = $.trim($('#CategoryDDL option:selected').text());
 
    if (selected_Category_ID.length == 0)
    {
        alert('Please select a Category.');
        return false;
    }
    else
    {
        //取得分類的產品總數
        CategoryProductCount(selected_Category_ID);
 
        var opt =
        {
            items_per_page: pageSize,
            num_display_entries: 5,
            prev_text: "上一頁",
            next_text: "下一頁",
            callback: PageSelectCallback
        };
        $("#Pagination").pagination(totalCount, opt);
    }
}

在function中,設定使用jquery.pagination的方法第二個參數有去特別指定顯示上一頁、下一頁的文字。

 

CategoryProductCount()

這個funcion將會執行AJAX操作,將頁面上選擇的分類ID送回後端的「ProductCount」Action方法,以取得該分類下的產品總數,

這個操作只會在每個分類被選擇後執行一次,並不會在每次執行分頁時去執行。

function CategoryProductCount(categoryId)
{
    var count = 0;
 
    if (categoryId.length == 0)
    {
        return count;
    }
    else
    {
        $.ajax({
            url: '@Url.Action("ProductCount", "Home")',
            data: { categoryId: categoryId },
            type: 'post',
            async: false,
            cache: false,
            dataType: 'json',
            success: function (data)
            {
                if (!data.Msg)
                {
                    count = parseInt(data.count, 10);
                    totalCount = count;
                }
            }
        });
    }
    return false;
}

 

PageSelectCallback()

function PageSelectCallback(page_index, jq)
{
    GetCategoryProducts(page_index + 1);
    return false;
}

這個就是jquery.pagination()方法中所指定的callback要執行的function,

在選擇產品分類下拉選單並且按下「List」Button後,就會執行第一個分頁資料的取得與顯示,

而這個callback方法所要接收的參數必須為:page_index以及jq,

page_index,這個是要顯示的分頁索引值,從零開始算,因為我後端取得分頁的PageIndex是從一開始算,所以這邊就做了「+1」的動作。

而「jq」這個則是指定Pager顯示容器的內容,看以下的圖示會比較清楚,

image

 

GetCategoryProducts()

這個function就是這一次主題的重心所在,

function GetCategoryProducts(pageIndex)
{
    if (selected_Category_ID.length == 0 || selected_Category_Text.length == 0)
    {
        alert('Please select a Category.');
        return false;
    }
    else
    {
        if ($.trim($('#CategoryDDL option:selected').val()) != selected_Category_ID.toString())
        {
            $('#CategoryDDL option[value=' + selected_Category_ID + ']').attr('selected', true);
        }
 
        $.ajax(
        {
            url: '@Url.Action("PageContent", "Home")',
            data: { page: pageIndex, categoryId: parseInt(selected_Category_ID, 10) },
            type: 'post',
            async: false,
            cache: false,
            dataType: 'json',
            success: function (data)
            {
                $('#table1 tbody').empty();
                $('#CategoryName').empty();
                $('#ProductNumber').empty();
 
                if (data.Msg)
                {
                    $('#Information').hide();
                    alert(data.Msg);
                }
                else
                {
                    $.each(data, function (i)
                    {
                        var item =
                        {
                            ProductID: data[i]["ProductID"],
                            ProductName: data[i]["ProProductNameductID"],
                            SupplierID: data[i]["SupplierID"],
                            CategoryID: data[i]["CategoryID"],
                            QuantityPerUnit: data[i]["QuantityPerUnit"],
                            UnitPrice: data[i]["UnitPrice"],
                            UnitsInStock: data[i]["UnitsInStock"],
                            UnitsOnOrder: data[i]["UnitsOnOrder"],
                            ReorderLevel: data[i]["ReorderLevel"],
                            Discontinued: data[i]["Discontinued"]
                        };
 
                        $('#table1 tbody').append($('#TemplateProduct').tmpl(item));
                    });
 
                    $('#table1 tbody tr:odd').css('background-color', '#F5FBFC')
 
                    $('#ProductNumber').html(totalCount);
                    $('#CategoryName').html(selected_Category_Text);
                    $('#Information').show();
                }
                return false;
            }
        });
    }
}

其實說穿了,這個方法與上一篇文章「ASP.NET MVC 3 資料套用範本 - 使用jQuery.Templates」中使用jQuery.Templates取得分類產品資料並且顯示的JavaScrtipt程式是相同的,

不同的地方在於,這個function要傳到後端「PageContent」Action方法的參數多了一個「page」,以取得指定的分頁資料。

 

大致上的程式內容就如上所示,不過要記得在View的頁面中要加入引用jquery.pagination的JS與CSS檔案,

<link href="@Url.Content("~/Content/pagination.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery.pagination.js")" type="text/javascript"></script>

 

那我們就再一次看看這個分頁功能的操作畫面,這一次也來觀察每次網路傳送與接收的情況,

 


這一次介紹了在ASP.NET MVC 3下如何使用jQuery.Templates與jQuery Pagination Plugin來完成分頁的功能,

其實要完成分頁功能需求的方式有很多種,這邊使用了一個比較簡單的方式來完成,雖然說簡單,但也蠻實用的,

下次一樣也是會說明有關ASP.NET MVC 3 + jQuery Templates的方頁,

不過Pager將會搭配使用之前所設計「MvcSimplePostPager」,

既然之前都已經完成了 MvcSimplePostPager 的HtmlHelper,也用來搭配jQuery.Templates試試看吧!

 

以上

沒有留言:

張貼留言

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。