上一篇文章「ASP.NET MVC 3 分頁 - 使用jQuery.Templates + jQuery Pagination Plugin」裡,
我們使用了「jQuery Pagination Plugin」這個jQuery Plugin來做為前端頁面Pager的解決方案,
然而這個 Pager 所提供的UI介面是有些陽春,
假如想要增加一些資料在上面讓使用者可以得到更多資訊的話,就要去更改「jquery.pagination.js」程式內容,
但其實在之前介紹「資料分頁」的時候,我們就已經建立了 MvcSimplePager 與 MvcSimplePostPager ,
這兩種Pager就已經提供了相當充足的分頁資訊,
接下來就會介紹如何以前端的jQuery Ajax的方式與jQuery Templates來完成分頁的需求功能。
進入主題前,先回顧一下之前的MvcSimplePager與MvcSimplePostPager,
MvcSimplePager
「ASP.NET MVC - 資料分頁(2) 自訂分頁功能列 MvcSimplePager」
這個Pager是單純使用Http Get的方式將分頁的Index傳送到後端後再去產生Pager以及顯示分頁的資料內容,
比較適合不需要做分類選擇而且不必帶其他參數的分頁資料顯示。
MvcSimplePostPager
「ASP.NET MVC - 資料分頁(3) 自訂分頁功能列 MvcSimplePostPager」
為了要保持表單上的分類選擇狀態以及顯示該分類的分頁資料,所以原本Http Get方式的Pager就無法沿用,
所以就以原本MvcSimplePager的Html.Helper架構再設計一個可供使用Http Post方式的Pager,
前端再搭配jQuery的事件來完成在使用Form的情境下的狀態保持及資料分頁的功能。
「ASP.NET MVC - 資料分頁(4) MvcSimplePostPager + AJAX」
MvcSimplePostPager搭配使用jQuery Ajax來完成需求功能,Pager以及分頁資料是後端輸出的部分檢視,
所以每一次的分頁除了分類的下拉選單不會重新Render外,其他的地方都會重新Render,
而這些變化都是以AJAX來完成,所以不會有畫面Reload的情況發生。
而這一次我們要做的分頁功能,每一個分類的分頁資料都還是維持使用jQuery.Templates方式來顯示分頁資料,
Pager的部份則會使用MvcSimplePostPager,因為MvcSimplePostPager上面的每個A元素都沒有另外指定事件,
所以當動態輸出到前端頁面時,就可以動態的去綁定前端處理事件,
不過這一次的作法會有所不同,之前所假設的情境是資料來源是同一個網站,而這一次我們必須假設資料來源有可能是其他的網站,
廢話不多說,就直接進入程式實作說明。
Controller
Action「PageMethod2」:此次分頁功能的主要進入頁面。
public ActionResult PageMethod2()
{
ViewData["CategoryDDL"] = categoryService.GenerateCategoryDDL(null);
return View();
}
Action「PagerContent」:接收前端所傳來的pageIndex, pageSize, totalItemCount參數資料,以PartialView回傳Pager內容。
public ActionResult PagerContent(int? page, int? pageSize, int? totalItemCount)
{
int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
ViewData["CurrentPage"] = currentPageIndex;
int page_size = pageSize.HasValue ? pageSize.Value : 10;
ViewData["PageSize"] = page_size;
int totalCount = totalItemCount.HasValue ? totalItemCount.Value : 0;
ViewData["TotalItemCount"] = totalCount;
return PartialView();
}
Action「ProductCount」:取得分類產品的總數。
[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「PageContent」:取得指定分類以及指定分頁的產品資料,回傳JSON格式的資料。
[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
PagerContent.cshtml:產出Pager的內容,這邊沒有任何的Model資料。
@using MVC3_Page.Helpers;
<div id="pager" class="pager">
@if (ViewData["CurrentPage"] != null && ViewData["PageSize"] != null && ViewData["TotalItemCount"] != null)
{
int currentPage = int.Parse(ViewData["CurrentPage"].ToString());
int pageSize = int.Parse(ViewData["PageSize"].ToString());
int totalItemCount = int.Parse(ViewData["TotalItemCount"].ToString());
@Html.Raw(Html.MvcSimplePostPager(currentPage, pageSize, totalItemCount, true));
}
</div>
PageMehtod2.cshtml:其中ID是PagerWrapperTop的DIV,為放置Pager的容器。
@{
ViewBag.Title = "PageMethod2";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div id="TableContent" class="div_default">
<h2>PageMethod2</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="PagerWrapperTop" class="PagerWrapper" style="text-align:left; : 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>
PageMethod2.cshtml 分頁資料的Templates內容:
<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>
PageMehtod2.cshtml JavaScript
開頭:
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 ButtonSearchEventHandler()
{
this.selected_Category_ID = $.trim($('#CategoryDDL option:selected').val());
this.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);
//取得產品分頁內容
GetCategoryProducts();
}
}
CategoryProductCount(取得分類的產品總數):
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;
}
GetCategoryProducts(取得產品的分頁資料內容):
先取得分頁的資料並顯示於頁面上之後,再去處理Pager的顯示內容以及Javascript事件綁定。
function GetCategoryProducts(pageIndex)
{
if (selected_Category_ID.length == 0 || selected_Category_Text.length == 0)
{
alert('Please select a Category.');
return false;
}
else
{
if (pageIndex == undefined || pageIndex.length == 0)
{
pageIndex = 1;
}
$.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();
//PageBar
PagerContent_Init(pageIndex)
}
return false;
}
});
}
}
PagerContent_Init(顯示Pager內容):
向後端的Action「PagerContent」取得PagerContent.cshtml的部分檢視內容。
function PagerContent_Init(pageIndex)
{
$.ajax(
{
url: '@Url.Action("PagerContent", "Home")',
data: { page: pageIndex, pageSize: pageSize, totalItemCount: totalCount },
type: 'post',
async: false,
cache: false,
dataType: 'html',
success: function (data)
{
$('#PagerWrapperTop').html(data);
Pager_Setting();
}
});
}
Pager_Setting(Pager內容的事件綁定):
//將Pager上面的連結項目的行為分離出來
//使用class方式做行為判別與動作執行
function Pager_Setting()
{
$('.PostPager').each(function (i, item)
{
$(item).css('cursor', 'pointer');
});
$('.PostPager.first-page').click(function () { GoToPage(1, selected_Category_ID); });
$('.PostPager.previous-page,.next-page,.last-page,.number-page').click(function ()
{
GoToPage($(this).attr('value'), selected_Category_ID);
});
}
function GoToPage(pageIndex, selectedCategoryID)
{
if (selectedCategoryID.length == 0 || selectedCategoryID == 0)
{
alert('Please select a Category.');
return false;
}
else
{
if ($.trim($('#CategoryDDL option:selected').val()) != selectedCategoryID.toString())
{
$('#CategoryDDL option[value=' + selectedCategoryID + ']').attr('selected', true);
}
GetCategoryProducts(pageIndex);
}
}
最後完成的分頁功能:
其實有關於資料分頁的處理有相當多種,必須依照你的需求來決定什麼樣的方式比較適合專案,
之前我做某一個MVC專案時,因為分頁的功能比較晚開發,所以一開始只是以MvcPaging的基本樣式來完成分頁,
一開始這種單純以Http Get(以連結的方式使用網址加上參數)的分頁還可以應付基本的分頁需求,
但是當系統功能加上表單也有了分類資料等類似的輸入條件時,就必須要想辦法讓頁面可以有分頁功能又要可以保持表單狀態,
一開始還會使用Session的方式來保持頁面表單的條件狀態,雖然可以達到同樣的結果,但是此舉卻遭到專案另一個團隊成員的「嫌棄」,
說什麼用Session很LOW、很笨、很耗記憶體之類的,於是請他就此需要來開發一套符合他要求的分頁套件,
我想大家都應該知道,當專案的團隊成員有這麼一個要挑剔又愛抱怨什麼功能不足的人,這個人十之八九會是個「嘴砲王」!
只會在那邊出張嘴,真正叫他做點事來看看卻什麼也拿不出來,唉~遇到這樣的團隊成員時,就是顯出其他團隊成員的真正價值的時候,
在當時就依據MvcPaging的原形而衍生出可以與Form表單整合的分頁,不過那時候的PostPager是在有限時間下倉促完成的,
以致於之後會再另外設計為「MvcSimplePager」以及「MvcSimplePostPager」,
之前與朋友聚會的時候,聽到在資料來源是外部網站時也可以利用jQuery.Templates來做分頁,所以就發展出jQuery.Templates相關的三篇文章,
之後還會就jQuery.Templates來說明以往在專案開發時的其他應用,如果各位不嫌棄的話就小小期待一下吧!
以上
沒有留言:
張貼留言