28 12月 2011

jQuery Plugin : DataTables (5)

前接jQuery Plugin : DataTables (4)

這裡開始的思路跟我早期的想法不一樣,主要原因是在DataTables call ajax 的時刻。
對我先前的BaseCRUD模式而言,在init時就會自DB取得第一頁的資料以供顯示。
如果透過DataTables來處理,就代表不需要在init階段處理這部份。
但無論如何,Search Form的存在還是必要的,DataTables第一次找回來的資料也必需符合Form初始化的選項;也就代表DataTables要能加入目前現有Form的欄位做為參數。

第一步還是先要訂個Form吧,並將submit改掉,改用button呼叫javascript。因為DataTables的聯絡對象是用“sAjaxSource“指定的,所以Form的action就沒有作用了。

	<form id="myform">
	<table>
		<tr><td>NAME:</td><td><input type="text" name="name" /></td></tr>
		<tr><td>ID:</td><td><input type="text" name="id" /></td></tr>
		<tr><td>PHONE:</td><td><input type="text" name="phone" /></td></tr>
		<tr><td colspan="2"><input id="btnSearch" type="button" value="Search" onclick="disTable.fnDraw();"/></td></tr>
	</table>
	</form>
至於disTable.fnDraw()就稍後再解釋。

第二步就要修改DataTables的呼叫,加入fnServerParams。

"fnServerParams": function ( aoData ) {
					$.merge(aoData, $("#myform").serializeArray());
				}
藉用jQuery.merge(),將Form裡的欄位資料加入DataTables ajax呼叫參數中。

第三步為了讓Button能觸發DataTables的更新,所以必需保留被DataTables enhanced 過的變數,然後以var_enhanced.fnDraw();來更新資料修改過的javascript 大約如下

	<script type="text/javascript">
		var disTable; //保留被DataTables enhanced 過的變數
		$().ready(function() {
			disTable = $("#sample").dataTable({
				"sPaginationType":"full_numbers",
				"bProcessing": true,
				"bServerSide":true,
				"sAjaxSource": '/jquery/DataTableServlet02',
				"fnServerParams": function ( aoData ) {
					$.merge(aoData, $("#myform").serializeArray());},
				"aoColumns": [
							  { "mDataProp": "id" },
				              { "mDataProp": "name" },
				              { "mDataProp": "phone" }
				          ]
			});
		});
	</script>

再來就是修改Search method用到的參數,與DataTables就無關了。

jQuery Plugin : DataTables (4)

前接jQuery Plugin : DataTables (3)

如果要讓DataTables完全聽命於Server端,無論大小時都要問過Server時,就要加入“bServerSide“來告訴DataTables。
只要設定“bServerSide“為true之後,無論是換頁、排序、搜尋,DataTables一定會與sAjaxSource聯絡來取得正確的結果。
Server與Client之間的溝通當然必需先講好各自要用的參數,請先參考Server-side processing,下列僅說明必要的部份

Sent to Server Side:

  • sEcho : Client端在每次呼叫sAjaxSource時會產生一個特定的sEcho做為驗証碼,Server端必需在JSON中回傳相同的值做為認證
  • iDisplayStart : 目前顯示的是第幾筆資料
  • iDisplayLength : 畫面上單次顯示的資料筆數

Reply from Server Sise:

  • sEcho : Client送來的驗証碼,直接回傳不要做改變
  • iTotalRecords : 未經過濾的資料總筆數
  • iTotalDisplayRecords : 經過濾的資料總筆數,但在大部份的使用上情形上幾乎同於iTotalRecords
  • aaData : 回傳的資料的JSON Array

所以稍為改一下javascript

	<script type="text/javascript">
		$().ready(function() {
			$("#sample").dataTable({
				"sPaginationType":"full_numbers", //顯示頁數而非僅有上下頁的按鈕
				"bProcessing": true, //在進行ajax呼叫時,會提示Processing,並防止Double submit
				"bServerSide":true,
				"sAjaxSource": '/jquery/DataTableServlet02',
				"aoColumns": [
				              { "mDataProp": "id" },
				              { "mDataProp": "name" },
				              { "mDataProp": "phone" }
				          ]
		});
		});
	</script>

Server這端可以自訂一個TO,再利用jackson這樣的library將TO轉為JSON字串。

public class DataTableTO<T> {
	private List<T> aaData;
	private String sEcho;
	private Integer iTotalRecords;
	private Integer iTotalDisplayRecords;
	//--省略getter/setter.
}
public static final String toJson(DataTableTO<?> dt) {
	ObjectMapper mapper = new ObjectMapper(); //do some registry
	return mapper.writeValueAsString(dt);
}

這樣還未竟全功,畢竟我們在做查詢時多半都是透過一個<Form>來進行。

jQuery Plugin : DataTables (3)

前接jQuery Plugin : DataTables (2)

經過前面的測試,雖然可以改變資料來源為動態而非固定值,但馬上遇到回傳格式的問題。
看看先前回傳的資料

{"aaData":[
	["A123","Adam","0910"],
	["B123","Bob","0819"],
	["C123","Child","0739"]
]}


這不就代表我Server端輸出時還要考慮property的順序?

 

所以當然要試著讓DataTables可以動態的指定每個column要顯示的property.
這就必需在兩邊都有改動。
Server端回傳的格式要改,像是下列這樣

{"aaData":[
	{"id":"A123","name":"Adam","phone":"0910"},
	{"id":"B123","name":"Bob","phone":"0819"},
	{"id":"C123","name":"Child","phone":"0739"}
]}

 

而在Client這端,也必需在呼叫datatable()時,以aoColumns + mDataProp 來設定每個column要顯示的property.

"aoColumns": [
			{ "mDataProp": "id" },
			{ "mDataProp": "name" },
			{ "mDataProp": "phone" }
			]

所以只要用下列的script來處理,就可以達到基本的使用需求

	<script type="text/javascript">
		$().ready(function() {
			$("#sample").dataTable({
				"sAjaxSource": './serverdata.txt',
				"aoColumns": [
				              { "mDataProp": "id" },
				              { "mDataProp": "name" },
				              { "mDataProp": "phone" }
				          ]
		});
		});
	</script>

 

再仔細確認看看,目前所有的操作仍是停留在Client端,接下來就要處理換頁時的Server端呼叫

jQuery Plugin : DataTables (2)

在我開發過的系統,沒有一個可以接受一次把所有資料撈出來後在Client上做分頁的。
所以Server端的回應模式一定要能被處理。

先理解DataTables做法的重點。

  1. 要自Server端取得資料,必需要有一個參數“sAjaxSource“指定資料的來源,資料來源可以是文字檔或是PHP,ASP,Servlet等程式的URL
  2. Server端回傳資料的格式,可以是JSON或XML,但以JSON為佳;回傳資料的property名稱要為aaData。
  3. DataTables會將回傳的資料更新table中<tbody></tbody>的部份。
  4. 自Server端取得資料的時機是在呼叫$("#tableId").dataTable();後,所以一開始的<tbody></tbody>內不需要有資料。

以純文字檔做為Server回傳資料的來源做個示範。
先將下列文字存為檔案serverdata.txt
{"aaData":[["A123","Adam","0910"],["B123","Bob","0819"],["C123","Child","0739"]]}

再建一個<tbody>為空的table

	<table id="sample" class="display">
		<thead>
			<tr>
				<th>ID</th>
				<th>Name</th>
				<th>Phone</th>
			</tr>
		</thead>
		<tbody>
		</tbody>
	</table>

最後呼叫DataTables的javascript method.

	<script type="text/javascript">
		$().ready(function() {
			$("#sample").dataTable({
				"sAjaxSource": './serverdata.txt'
		});
		});
	</script>

就可以看到下列的結果
Server Side Response(跟之前一樣才是....)

jQuery Plugin : DataTables (1)

 

去年曾經有幸,短時間加入了X稅局的案子,大部份使用的技術都還算熟悉,像是SpringMVC, JPA, Maven這些東西,比較少接觸的大概是像jquery的眾多plugin,DataTables是其中之一。由於我自已是有習慣的分頁查詢處理模式,在當下我並沒有很喜愛這個Plugin,因為在各方面比較之下,我覺得我常用的模式要寫的程式碼並不會比較多,而且對於我BaseCRUD的操作模式有所影響。所以在prototyping 時我是將我常用的模式硬加在DataTables之上。不過沒幾個星期我就脫離案子,後續也沒再深入瞭解。

不過前段時間又有些新想法,記起了這個jQuery Plugin,稍為試了下順便做些筆記。以下的東西可能會有錯誤的部份...

DataTables的網站請參考:DataTables

最基本的例子,針對目前Html中現有的table加工,讓table裡的資料變得可以被分頁、排序及查詢。

table要注意的部份
(1)應該要有id,或特定的標記,以供DataTables識別出要處理的對象
(2)要有thead,tbody,tfoot的分別,tfoot可有可無,但還是建議加上。
(3)css部份,請import Datatables 提供demo_table.css,並將class設定為"display"

最基本的格式就像下列這樣

	<table id="sample" class="display">
		<thead>
			<tr>
				<th>ID</th>
				<th>Name</th>
				<th>Phone</th>
			</tr>
		</thead>
		<tbody>
			<tr>
				<td>A12345</td>
				<td>Adam</td>
				<td>09301234</td>
			</tr>
			<tr>
				<td>B12345</td>
				<td>Bob</td>
				<td>09301234</td>
			</tr>
			<tr>
				<td>C12345</td>
				<td>Child</td>
				<td>09301234</td>
			</tr>
		</tbody>
		<tfoot>
			<tr>
				<th>ID</th>
				<th>Name</th>
				<th>Phone</th>
			</tr>
		</tfoot>
	</table>

 

 

再加上javascript

	<script type="text/javascript">
		$().ready(function() {
			$("#sample").dataTable();
		});
	</script>

然後就可以看到下列這樣的結果。
DataTables Demo

這種分頁的效果算是客戶端分頁,因為必需一次提供所有的資料,除非重新更新頁面,否則無論是換頁或搜尋,Datatables都不會與Server端有任何溝通。

這種模式當然也有適用的時候,但對於資料量較大的系統而言,應該是會去避免使用。