jQuery Datatables 1.10+ & ASP.NET MVC with Server Side Integration
前言
工作上使用jQuery DataTables 套件時,個人比較推薦採用Server Side模式開發
一啟用Server Side模式後,當用戶點擊分頁、排序時,DataTables會自動向Server端發出Ajax,並自帶一些參數↓
服务器处理(server-side) 手册 Datatables中文网 也有ServerSide模式的詳細說明
以下是啟用Server Side模式的範例,serverSide:true,並且同時要給ajax參數,否則會報錯
不過DataTables如此的設定,會造成畫面第一次載入時,就會自動向Server端發出Ajax,某方面來說是個效能問題
參考此文章:Disable initial automatic ajax call - DataTable server side paging
還須要加入一個參數:"deferLoading": 0
中文文件說明:deferLoading 延迟服务器加载数据直到第二次绘制
2018.4.9追記:雖然本範例使用Ajax Get Method來送資料給Server端,但如果畫面上的資料行或查詢條件一多的話,有可能碰上HTTP Error 404.15 - Not Found 送給Server端的QueryString太長的問題
解決辦法兩種:
1.DataTable發出的Ajax改用Post Method
2.或更改Web.config設定 How to configure the web.config to allow requests of any length
實作
1.在畫面上放置一個表單,當做查詢條件使用
2.放置DataTables的表格和資料行名稱
3.初始化DataTable()時,設定以下參數:
serverSide:true (啟用ServerSide模式)、
searching: false 關閉filter功能,因為工作上大都用不到 (官網 searching 文件)
deferLoading: 0 (畫面一開始載入不發出ajax撈資料)
processing: true會讓讀取資料時,出現「Processing...」字眼,個人覺得滿醜所以拿掉它XD(我習慣採用jQuery blockUI 下一篇文章會談到如何使用自己的Loading效果)
columns設定DataBinding的資料行名稱
設定ajax參數(和jQuery的$.ajax()裡的參數名稱幾乎一樣),須留意ajax的data參數要用function的方式設定,如此每次發出Ajax時才會重新抓表單裡的輸入值
參考:DataTables.js → How to update your data object for AJAX JSON data retrieval 和 DataTables Server-side Processing with Custom Parameters in CodeIgniter
2018.4.5 追記:如果畫面上的查詢條件很多的話,ajax裡的data參數不就一行一行寫到天荒地老XD?,為了減少程式碼個人推薦使用jQuery extend()搭配jQuery serializeObject();套件
可以改寫如下
※提醒:和原生的jQuery serialize()方法有所不同,jQuery serializeObject套件並不會把中文的值做UrlEncode,它仍會保留原本中文的值
※目前已知此套件遇到type="email"的欄位,無法序列化為物件的Property,把type="email"改成type="text"即可
但和原生jQuery serialize()同樣的是,當checkbox沒勾時,序列化後的結果並沒有checkbox的name和value,如此傳遞到Server端就會是null
ajax: {
method:"get",
url: "@Url.Action("GetData_Full", "Home")",
data: function (d)
{//↓新寫法
let formObj = $("form[name=myForm]").serializeObject();
//額外處理checkbox(因為沒勾選時,會是null)
$("form[name=myForm] input:checkbox").each(function (i, chk) {
formObj[chk.name] = chk.checked;//chekcbox是否勾選
});
//↓寫一行就好
$.extend(true, d , formObj);
}
}
設定order參數預設哪個資料行排序,參考官網:Default ordering (sorting)
order參數沒設定的話,預設值為:order: [[0, "asc"]]
或參考此文章關閉一開始資料的排序( order:[] ):Is there a way to disable initial sorting for jquery DataTables?
↑會有這需求,通常為要排序的資料行不在畫面上,而由Server端決定,例如:異動時間
關閉orderMulti參數("orderMulti": false),因為會增加排序處理複雜度、資料處理時間:orderMulti
4.最後表單的按鈕click時,執行 table.draw(); 來載入資料
View完整的代碼↓
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>表單的Button click後才查資料(分頁、排序)</title>
<!--引用dataTables css-->
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css" />
</head>
<body>
<!--表單↓通常放置查詢條件-->
<!--action在這裡可以不用給,因為發出ajax時就會指派url-->
<form name="myForm" action="" method="post">
<label>MyTitle:</label> <input type="text" name="MyTitle" /><br />
<label>MyMoney:</label> <input type="text" name="MyMoney" /><br />
<input type="button" id="btnQuery" value="查詢" />
</form>
<!--DataTables的表格-->
<table id="myDataTalbe" class="display">
<thead>
<tr>
<th>#</th>
<th>MyTitle</th>
<th>MyMoney</th>
</tr>
</thead>
</table>
<!--引用jQuery-->
<script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.js"></script>
<!--引用dataTables.js-->
<script type="text/javascript" src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>
<script type="text/javascript">
$(function () {
let table =
$("#myDataTalbe").DataTable({
/* processing: true,*/ //→這太醜了,所以關閉
searching: false, //關閉filter功能
columns: [ //指定Server端的資料行繫結名稱
{ data: "sysid" },
{ data: "MyTitle" },
{ data: "MyMoney" }
],
serverSide: true,//啟用ServerSide模式
//ajax參數在1.9版以前參數名稱為sAjaxSource
ajax: {
method:"get",//或post,自由決定,影響到Server端用FormCollection取值或Request.QueryString取得DataTables傳遞的資訊
url: "@Url.Action("GetData_Full", "Home")",
data: function (d)
{
d.MyTitle = $("input[name=MyTitle]").val();
d.MyMoney = $("input[name=MyMoney]").val();
}
},
deferLoading: 0, //初始化DataTable時,不發出ajax
order: [[0, "asc"]], //預設排序資料行(由0算起)
orderMulti : false
});
$("#btnQuery").click(function () {
//按下表單的查詢按鈕後才發出Ajax載入資料
table.draw(); //或table.ajax.reload();
});
});
</script>
</body>
</html>
而Server端要回傳的資料格式,大概長這樣↓
draw:為了避免XSS攻擊,DataTables傳遞什麼值,Server端就跟著回傳什麼值
recordsTotal:經過查詢後的資料總筆數
recordsFiltered:再度經過filter後的資料總筆數,由於本範例未使用filter功能,所以此數值和recordsTotal一樣
recordsTotal和recordsFiltered兩個數值影響到的是下面紅框的呈現,最好別亂給值
data:要回傳的資料,注意陣列中的每一筆物件,其屬性名稱要和DataTables()裡的columns名稱對得上
完整Controller代碼↓
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
//透過NuGet加入System.Linq.Dynamic,Server端Linq排序用得到
using System.Linq.Dynamic;
using System.Text;
using System.Threading;
using System.Web;
using System.Web.Mvc;
namespace WebDataTables.Controllers
{
/// <summary>
/// 每一筆資料Entity
/// </summary>
public class MyRecord
{
public int sysid { get; set; }
public string MyTitle { get; set; }
public int MyMoney { get; set; }
}
public class HomeController : Controller
{
/// <summary>
/// DataSource 資料集合,通常為DB裡的資料
/// </summary>
private List<MyRecord> _myRecords = new List<MyRecord>();
public HomeController()
{//在建構子裡新增資料
for (int i = 0; i < 300; i++)
{
this._myRecords.Add(new MyRecord()
{
sysid = i + 1,
MyTitle = "MyTitle" + i,
MyMoney = i * 1000
});
}//end for
}
/// <summary>
/// 呈現畫面
/// </summary>
public ActionResult Index()
{
return View();
}
/// <summary>
/// 查詢資料
/// </summary>
public ActionResult GetData_Full(int draw, int start, int length,//→此三個為DataTables自動傳遞參數
//↓以下兩個為表單的查詢條件,請依自己工作需求調整
string MyTitle, int? MyMoney)
{
int skip = start;//起始資料列索引值(略過幾筆)
#region jQuery DataTables的排序資料行
//jQuery DataTable的Column index
string col_index = Request.QueryString["order[0][column]"]; //←↓如果是接post method的話,記得改成Request.Form["order[0][column]"]
//col_index 換算成 資料行名稱
//排序資料行名稱
string sortColName = string.IsNullOrEmpty(col_index)? "sysid" : Request.QueryString[$@"columns[{col_index}][data]"];
//升冪或降冪
string asc_desc = string.IsNullOrEmpty(Request.QueryString["order[0][dir]"]) ? "desc" : Request.QueryString["order[0][dir]"];//防呆
#endregion
//查詢&排序後的總筆數
int recordsTotal = 0;
//要回傳的分頁資料
List<MyRecord> pagedData = new List<MyRecord>();
//總資料
var query = this._myRecords.AsEnumerable();
//查詢
if (!string.IsNullOrEmpty(MyTitle))
{
query = this._myRecords.Where(m=>m.MyTitle.Contains(MyTitle));
}
if (MyMoney.HasValue)
{
query = this._myRecords.Where(m=>m.MyMoney==MyMoney);
}
//排序
query = query.OrderBy($@"{sortColName} {asc_desc}"); //排序使用到System.Linq.Dynamic
recordsTotal = query.Count();//查詢後的總筆數
if (length==-1)
{//抓全部資料
pagedData = query.ToList();
}
else
{//分頁
pagedData = query.Skip(skip).Take(length)
.ToList();
}
//回傳Json資料
var returnObj =
new
{
draw = draw,
recordsTotal = recordsTotal,
recordsFiltered = recordsTotal,
data = pagedData//分頁後的資料
};
return Json(returnObj, JsonRequestBehavior.AllowGet);
}
}
}
執行結果:
結語
想更進一步熟悉DataTables還有什麼其它寫法的人,可以再參考其他網友文章
Datatables 在asp.net mvc中的使用 - 醉丶千秋 - 博客园
Using jQuery DataTables with Server-Side Processing with ASP.NET MVC - CodeProject