8.前置作業做的差不多了,接著我們先將資料庫匯入專案內,而小弟這邊用的資料庫是用微軟提供的 NorthWind 當範例,如果有需要的朋友們也可以到微軟官方下載 Northwind and pubs Sample Databases :

161925842.png

9.再來我們在到 Model 中新增一個類別為 ProductDTO.cs ,而一般實務上很少會返回所有的資料表欄位給使用者看,所以我們新增一個類別來做轉換:

1public class ProductDTO
2{
3    public int ProductID { get; set; }
4    public string ProductName { get; set; }
5    public string QuantityPerUnit { get; set; }
6    public decimal? UnitPrice { get; set; }
7}

10.接著我們繼續完成我們 Web API 的 Function ,首先我們先引用

1using MvcGridView.Models;

然後再裡面新增一個 Function 名為 GetProducts,這邊我也透過剛剛的那個 ProductDTO 來做欄位轉換的動作,這樣就可以確保返回頁面給使用者的欄位都是我們要的。

01public class ProdcutController : ApiController
02{
03    NorthwindEntities db = new NorthwindEntities();
04
05[Queryable]
06public IQueryable<productdto> GetProduct()
07{
08    return db.Products.Select(p => new ProductDTO
09    {
10    ProductID = p.ProductID,
11    ProductName = p.ProductName,
12    QuantityPerUnit = p.QuantityPerUnit,
13    UnitPrice = p.UnitPrice
14    });
15  }
16
17}</productdto>

另外這邊需要注意的是,在 GetProduct 中加上了 [Queryable] 的屬性,加上後我們才能使用 OData,不過過如果你的 VS 2012 是 Update 2 以下的話,可能還是要先透過 NuGet 來安裝 Odata 的套件,而究竟什麼是 OData ?OData 全名為 Open Data Protocal  在官方網站可以看到 It’s an open web protocol for querying and updating data. 屬於一個開放的網路協定,負責用來作資料的查詢以及更新,簡單來說他能透過前端網址傳送過來的參數直接幫我們來對資料庫進行過濾的動作,根本非常強大,稍後我們的分頁也會透過 OData 來處理,如果有興趣的朋友也可以到 OData 的官方網站看看 ~

做到這邊我們的前置作業也做的差不多了,接下來就是進入我們核心的 jQuery 部分了,在開始之前我們先看看現在我們的網站長什麼樣子:

162333443.png

再接再厲!!!

化腐朽為神奇的 jQuery & CSS

1.我們先完成分頁的部份,而這邊會用到剛剛前面提到的 OData ,透過網址傳遞參數的方式直接來為我們做資料的查詢,EX:localhost/api/GetProducts?$skip=10&$top=10 ,$skip 代表會跳過10筆資料,然後 $top 會抓前10筆資料,這樣就可以輕鬆的做到分頁的概念 ~

01$(function () {
02    PagerView(0); // 頁面載入時先Load第一筆資料
03    $('a.pageList').click(function () {
04        var page = $(this).data("page") - 1 * 1;
05        PagerView(page);
06    });
07});
08
09function PagerView(page) {
10    $.getJSON("/api/Product?$skip=" + page * 10 + "&$top=10", function (data) {
11    var arr = [];
12    $("#GridTable th").each(function () {
13        arr.push($(this).data("name"));
14    });
15    var tr = "";
16    for (var i = 0; i <= data.length - 1; i++) {
17        tr += "<tr>" +
18        "<td>" + data[i][arr[0]] + "</td>" +
19        "<td>" + data[i][arr[1]] + "</td>" +
20        "<td>" + data[i][arr[2]] + "</td>" +
21        "<td>" + data[i][arr[3]] + "</td></tr>";
22    }
23    $("#GridContent").html(tr);
24  });
25}

使用 $.getJSON 來呼叫我們後端的 Web API,而為回傳的資料為 JSON Object ,並透過 for 迴圈來串成字串,最後再塞到我們的 tbody 裡面,而做到這邊我們總算能看到資料了(感動)。

2.既然是 GridView 那一定缺少不了編輯 TD 的功能,所以我們在 document.ready 事件最下面加上 :

01$(document).delegate("#GridContent td", "click", function () {
02    var $this = $(this);
03    // 假如有input則返回
04    if ($this.has("input#edit_input").length > 0)
05        return false;
06    else
07      $("#edit_input").closest("td").text($("#edit_input").val());  // 將input的值填入td
08
09    var text = $this.text(); // 取得目前 td 的值
10    $this.html("<inputtype='text'id='edit_input'value="+text+"/>");
11    $this.find("#edit_input").val(text); // 將原本td的值給input
12    return true;
13});

這個方法不難,每次使用者點了 TD 之後會先取得舊的 input 並透過 .closest("td") 找出其 td 並填入 input 的值,接下來在使用 .text() 的方法取得當下 td 的值,在利用 .html 將 input 加入當下的 td 中。

3.再來就是我們的 jQuery UI 派上用場的地方了,還記得前面說過我們的 GridView 可以讓使用者改變 TH 大小的以及改變 TH 順序的功能嘛 ,所以我們會用到 jQuery UI 的 Resizable 和 Sortable 這兩個 plug-in 了,如果對這兩個方法不熟的朋友可以先到 jQuery UI 官網看看官網的範例,jQuery-UI-Resizable 、jQuery-UI-Sortable,這邊我們先看看如何實作 TH 改變大小的功能:

我們先在最上方 CSS 區塊加上簡單的 CSS:

01@section styles
02{
03    <style>
04      .ui-resizable-helper {
05        border: 2px dotted #00F;
06    }
07
08    table tr th {
09      width: 150px;
10      border: 1px solid #000;
11      padding: 5px;
12      height: 22px!important;
13      overflow: hidden;
14      text-overflow: clip;
15      white-space: nowrap;
16    }
17
18    table tr td {
19      height: 22px;
20      border: 1px solid #000;
21      padding: 0 2px 0 2px;
22      overflow: hidden;
23      white-space: pre;
24      text-overflow: clip;
25    }
26
27    #edit_input {
28      height: 22px;
29    }
30  </style>
31}

接著完成我們 jQuery 的部份,一樣加在 document.ready 的最下面。

01var $this = $("#GridTable");
02var width = $this.width(); // 用來存放Table的寬度
03$this.css("table-layout", "fixed");
04
05$this.find("th").resizable({
06    minWidth: 0, //最小寬度
07    helper: "ui-resizable-helper", //
08    handles: "e",
09    stop: function (event, ui) {
10      //停止後重新記算table的寬度
11      width = width - ui.originalSize.width + ui.size.width;
12      $this.width(width);
13    }
14});

首先第一段第一段宣告了 width 當成全域變數,目的就是用來存放目前 Table 的寬度,接著我們對每個 th 透過 each 都加上 resizable() 方法 ,而 stop 的方法代表當拖拉結束時要做的事情,我們重新計算 width 的大小,並且填入 table 內,另外 helper 的屬性加上了 ui-resizable-helper , resizable 會幫我們在拖拉時產生一個 class="ui-resizable-helper" 的 div,在搭配 CSS 加上border的屬性,就會有類似在拖拉時有輔助格線的感覺了。

4. 最後,就是我們的 TH 改變順序的功能了,利用 sortable 的方法來做也非常簡單:

01var old_index = 0;
02$this.sortable({
03    items: "th", // 建立排序的項目
04    cursor: "move", // 滑鼠的游標圖案
05    placeholder: "ui-state-highlight",
06    axis: "x", // 只允許橫向移動
07    start: function (event, ui) {
08      old_index = ui.item.index();
09    },
10    update: function (event, ui) {
11      if (old_index < ui.item.index()) {
12        $this.find("tr").each(function () {
13 $(this).find("td").eq(old_index).insertAfter($(this).find("td").eq(ui.item.index()));
14        });
15      }
16      else {
17        $this.find("tr").each(function () {
18$(this).find("td").eq(old_index).insertBefore($(this).find("td").eq(ui.item.index()));
19        });
20      }
21    }
22}).disableSelection();

完成後的 GridView 為這樣:


163344635.png

MvcGridView.rar

總結

寫這篇文章從範例到撰寫就花了小弟×××天的時間,而我們的 GridView 搭配 jQuery UI 來做真的非常方便,小弟個人滿偏好 jQuery UI 這個 Plug-in 的,像是 DatePicker 、Dialog、Spinner 都是網頁上滿常看到的應用,而有下載 Code 回去研究的朋友也可以發現,TH、和 TD 其實也透過 CSS 做到如果內容超過寬度會自動隱藏而不會換行,這個個人覺得也算是一種需求所以就在 CSS 上加上去了,而我們的 GridView 雖然很陽春,但是如果經過美編人員幫我們美化一下還是可以上線的,不過當然還是得依需求來決定要自己 Code 還是用現成的套件來完成。


新手發文,如有錯誤煩請告知,感謝。

如果喜歡我的文章請按推薦,有任何問題歡迎下面留言~~~

常逛Web:

ithome

mobile01

ruten

developerfusion


簽名:

學習這條路很廣,喜歡什麼技術不重要,重要的是你肯花時間去學習

(這句話 個人很喜歡)


文章出處: http://www.dotblogs.com.tw/jasonyah/archive/2013/05/19/use.jquery-ui.do.gridview.with.asp.net-mvc4.aspx