MVC Paging
Bài đăng này đã không được cập nhật trong 3 năm
Paging là từ mà chúng ta không thể không nhắc tới mỗi khi phát triển một ứng dụng website. Vậy khi phát triển ứng dụng web bằng MVC thì chúng ta sẽ paging bằng cách nào, hôm nay mình xin chia sẻ 1 trong số những cách để thực hiện paging trên size
trong bài viết này mình sẽ thực hiện paging từ BASIC html thuần cho tới việc paging có connect với DB.
Đầu tiên chúng ta hiểu quy trình paging sẽ thực hiện như thế nào
- Sơ đồ luồng dữ liệu sẽ đi khi thực hiện paging
OK mình sẽ bắt đầu thực hiện công việc nào mình sẽ demo với database gồm 2 table là Orders và Customers có diagram như bên dưới
phần View trong demo này sẽ có yêu cầu như sau:
- khi vào page thì default page = 1
- load page số 1 với page size đc quy định trong web config
- Khi click vào page nào thì sẽ list data theo page đó
ở đây mình có data là 100 row, mỗi page là 10 row
File HTML để hiển thị
@{
ViewBag.Title = "Tutorial MVC Paging";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<script src="~/Scripts/OrderApp/OrderAppJS.js"></script>
@model List<Business.ViewModel.OrdersViewModel>
<div class="container">
<div class="row" style="text-align:center">
<h1>Orders Management</h1>
</div>
<div class="row">
<div class="col-lg-12">
<table class="table" id="tbl-order">
<thead>
<tr>
<th>
ID
</th>
<th>
Order Date
</th>
<th>
Status
</th>
<th>
Customer
</th>
<th>
Country
</th>
<th>
Total
</th>
</tr>
</thead>
<tbody>
@for (int i = 0; i < Model.Count; i++)
{
<tr>
<td>@Model[i].Id</td>
<td>@Model[i].OrderDate.ToString("MM/dd/yyyy")</td>
<td>@Model[i].Status</td>
<td> @Model[i].CustomerName</td>
<td>@Model[i].CountryName</td>
<td>$@Model[i].TotalPay</td>
</tr>
}
</tbody>
<tfoot>
<tr>
<td colspan="6" style="text-align:right">
@for (int i = 1; i <= (int)@ViewBag.TotalPage; i++)
{
<a href="#" onclick="OrderAppJs.Paging(@i)">@i</a>
}
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
Config Page Size
<configuration>
<appSettings>
<add key="DefaultPageSize" value="10" />
</appSettings>
</configuration>
đây là controller cho lần vào page đầu tiên mục tiêu trả về là:
- 10 row đầu tiên
- tổng số page
public ActionResult PagingSite()
{
int totalRow = 0;
int totalPage = 0;
var pageSize = int.Parse(WebConfigurationManager.AppSettings("DefaultPageSize"))
var listOrder = OrderAppBusiness.GetListOrder(1,pageSize, out totalRow);
if (totalRow > pageSize)
{
totalPage = (int)Math.Ceiling((decimal)(totalRow / pageSize));
if ((totalRow % pageSize) > 0)
{
totalPage += 1;
}
}
else
{
totalPage = 1;
}
@ViewBag.TotalPage = totalPage;
return View(listOrder);
}
ok chúng ta đã load đc form cho lần đầu tiên, giờ chúng ta sẽ chuyển qua bước thứ 2 là paging
-
mục tiêu của chúng ta là:
- click page nào thì sẽ load data cho page đó
-
thế mạnh của MVC là partial view kết hợp với Ajax để load data ở những vùng cần thiết mà ko cần reload lại toàn bộ page vì thế nó rất nhanh.
-
tùy vào những yêu cầu đó mà chúng ta có thể sử dụng linh hoạt object trả về của controller (Json, partialView, ...). Ở đây mình đơn thuần chỉ trả về các row của table rồi append vào table đã có sẵn nên controller sẽ trả về là 1 parrtial view
var OrderAppJs = {
Paging: function (page) {
$.ajax({
data: { page: page },
dataType: "html",
url: "/Home/PagingSite",
success: function (data) {
$("#tbl-order tbody").empty();
$("#tbl-order tbody").append(data);
}
});
}
}
public ActionResult PagingSite(int page)
{
int totalRow = 0;
var pageSize = int.Parse(WebConfigurationManager.AppSettings("DefaultPageSize"))
var listOrder = OrderAppBusiness.GetListOrder(page,pageSize, out totalRow);
return PartialView(listOrder);
}
@model List<Business.ViewModel.OrdersViewModel>
@for (int i = 0; i < Model.Count; i++)
{
<tr>
<td>@Model[i].Id</td>
<td>@Model[i].OrderDate.ToString("MM/dd/yyyy")</td>
<td>@Model[i].Status</td>
<td>@Model[i].CustomerName</td>
<td>@Model[i].CountryName</td>
<td>$@Model[i].TotalPay</td>
</tr>
}
Follow đoạn code trên như sau
- user click vào panel paging ở table footer
- Ajax truyền request lên sever, ở đây là page cần lấy data
- Controller nhận request, gọi code behavior để xử lý lấy data cho page request, sau khi nhận đc data thì controller đi render Partial view và trả về cho Ajax 1 chuỗi strinhg chính là code html dể append vào table
- Ajax sau khi complete phiên làm việc thì sẽ nhận đc 1 chuỗi string các row và tiến hành clear body hiện tại và append các row mới vào body table.
Như mình nói lúc nãy Controller ngoài trả về View, PartialView thì mình có thể trả về Json để tiện xử lý 1 số business. Vậy làm sao mình có thể kết hợp vừa trả về view và vừa trả về 1 số object khác. Mình cũng xin chia sẽ thể 1 cách follow như thế này
- View hoặc PartialView sẽ được render thành chuỗi string và gán vào Json
- Controller trả về là Json và Ajax sẽ lấy html code từ Json trả về
Các bạn có thể follow theo code bên dưới code Controller
public ActionResult PagingSite(int page)
{
int totalRow = 0;
var pageSize = int.Parse(WebConfigurationManager.AppSettings("DefaultPageSize"))
var listOrder = OrderAppBusiness.GetListOrder(page,pageSize, out totalRow);
return Json(new { Grid = RenderRazorViewToString("PagingSite", listOrder) }, JsonRequestBehavior.AllowGet);
}
public string RenderRazorViewToString(string viewName, object model)
{
ViewData.Model = model;
using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext,
viewName);
var viewContext = new ViewContext(ControllerContext, viewResult.View,
ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}
Paging: function (page) {
$.ajax({
data: { page: page },
url: "/Home/PagingSite",
success: function (data) {
$("#tbl-order tbody").empty();
$("#tbl-order tbody").append(data.Grid);
}
});
}
}
Còn về code Behavior thì Mình sẽ sử dụng EF (Entity Framework) để thực hiện paging lấy data
- đầu tiên mình thực hiện setup cho EF
namespace Business.UnitOfWork
{
public class OrderAppUnitOfWork : BaseUnitOfWork
{
public OrderAppUnitOfWork(OrderAppEntities entity)
: base(entity)
{
}
public IOrderRepository OrderRepository
{
get
{
return new OrderRepository(this);
}
}
public ICustomerRepository CustomerRepository
{
get
{
return new CustomerRepository(this);
}
}
}
}
namespace Business.Repository
{
public interface IProductRepository : IBaseRepository<Product>
{
}
}
namespace Business.Repository
{
public interface IBaseRepository<T> where T : class
{
T Save(T model);
void Save(IEnumerable<T> models);
void Delete(T model);
void Delete(int id);
void Delete(IEnumerable<T> models);
T GetObject(int Id);
IQueryable<T> GetAll();
}
}
Chi tiết về setup Responsitory mình sẽ update vào bài sau nhé ^^
giờ chúng ta đã setup xong EF, công việc tiếp theo là đi thực hiện paging để lấy dữ liệu.
Để thực hiện việc vận chuyển data mình đã define ra các model sau
public class OrdersViewModel
{
public int Id { get; set; }
public DateTime OrderDate { get; set; }
public string Status { get; set; }
public string CustomerName { get; set; }
public string CountryName { get; set; }
public decimal TotalPay { get; set; }
public int TotalQuantity { get; set; }
}
để thực hiện công việc này mình tạo 1 layer nằm giữa Controller và Entity FrameWork, mục đích chính của layer này là sẽ xử lý các business, gọi EF xử lý data và trả về cho controller data cần thiết.
namespace Business.Business
{
public class OrderAppBusiness : BaseBusiness
{
/// <summary>
/// currentPage => nextpage = currentPage + 1
/// pageSize => row display per page
/// totalRow => total data row in database
/// </summary>
public List<OrdersViewModel> GetListOrder(int currentPage,int pageSize, out int totalRow)
{
var listOder = this.OrderAppUnitOfWork.OrderRepository.GetAll().Include(x => x.Customer).Include(x => x.OrderDetails);
List<OrdersViewModel> listResult = new List<OrdersViewModel>();
//count total data row in database
totalRow = listOder.Count();
//Paging => get data from currentPage - 1 * pageSize to (currentPage * pageSize) + pageSize
listOder = listOder.Skip((currentPage - 1) * pageSize)
.Take(pageSize);
//Mapping to model
foreach (var item in listOder.ToList())
{
OrdersViewModel order = new OrdersViewModel()
{
Id = item.Id,
CustomerName = item.Customer.Name,
CountryName = item.Customer.Country,
OrderDate = item.OrderDate.Value,
Status = item.Status,
TotalPay = item.OrderDetails.Select(y => y.Quantity * y.UnitPrice).Sum()
};
listResult.Add(order);
}
return listResult;
}
}
}
Vậy là xong
All rights reserved