用jQuery在MVC上做類似GridView的編輯效果
在MVC上開發由於缺少了Control的幫助,因此很多東西必須要手動完成。
但這也讓我體會到jQuery有趣的地方,今天來練習用jQuery做出類似GirdView在編輯資料時的效果。
首先還是先利用北風資料庫撈出一些產品資料來用
Controller
public class HomeController : Controller
{
private MyDataContext db;
public HomeController()
{
db= new MyDataContext();
}
public ActionResult Index()
{
return View(db.Products);
}
}
View
<table>
<tr>
<th>
ProductID
</th>
<th>
ProductName
</th>
<th>
QuantityPerUnit
</th>
<th>
UnitPrice
</th>
<th>
UnitsInStock
</th>
<th>
UnitsOnOrder
</th>
<th>
ReorderLevel
</th>
<th>
Discontinued
</th>
<th></th>
</tr>
<% foreach (var item in Model) { %>
<tr>
<td>
<%= Html.Encode(item.ProductID) %>
</td>
<td><%= Html.Encode(item.ProductName) %></td>
<td>
<%= Html.Encode(item.QuantityPerUnit) %>
</td>
<td><%= Html.Encode(String.Format("{0:F}", item.UnitPrice)) %></td>
<td>
<%= Html.Encode(item.UnitsInStock) %>
</td>
<td>
<%= Html.Encode(item.UnitsOnOrder) %>
</td>
<td>
<%= Html.Encode(item.ReorderLevel) %>
</td>
<td>
<%= Html.Encode(item.Discontinued) %>
</td>
<td>
<a href="#" onclick="returnEdit(<%=item.ProductID %>,this)">編輯</a>
</td>
</tr>
<% } %>
</table>
準備工作完成,接下來開始寫jQuery
<a href="#" onclick="returnEdit(<%=item.ProductID %>,this)">編輯</a>
我先在編輯的連結上綁一個click事件,當按下的時候,去呼叫returnEdit這個function,帶入ProdictID跟this當參數
接著開始寫function
function returnEdit(ProductID, data) {
var pricetd = $(data).parent().parent("tr");
//抓傳進來的參數data,也就是只編輯的連結本身,用parent()抓他的父元素
//連用兩次,代表我要抓父元素的父元素的tr
var s = pricetd.children("td").eq(3);
//用eq(3) 表示我要抓第四個td
s.html("<input type='test' value='" + s.text() + "' style='width:50px;'/>");
//在這個td下的html,改為input,value放入原本的text()
$(data).css("display", "none").parent()
.append("<span id='SumitOrCancel'><a href='#' onclick='returnSumit(this," + ProductID + ")'>確定</a> |<a href='#' onclick='returnCancel(this)'>取消</a></span>");
//然後將編輯的按鈕加入css的display:none隱藏起來,在加入確定跟取消的連結,各綁定一個click事件
}
寫完之後,當按下編輯按鈕時,畫面就會從原先的
變成,
這樣,接著繼續來寫按下確定之後,利用jQuery提供的load(),完成更改價格的效果
//傳入兩個參數,一個是ProdcutID,另一個是連結本身
function returnSumit(data, ProductID) {
var pricetd = $(data).parent().parent().parent("tr");
//抓他父父父元素的tr !!注意!!這邊用三個parent()是因為連結又多包了一個span
var s = pricetd.children("td").eq(3);
//一樣抓第四個td
s.load("/Home/EditPrice", { price: s.children("input").val(), productID: ProductID }, function () { $(data).parent().prev().css("display", ""); $("#SumitOrCancel").remove(); });
//利用load去呼叫後端的程式,傳入兩個參數分別是輸入的價格以及ProductID
//當完成之後,將編輯的連結顯現,並將確定跟取消的連結隱藏
}
後端的Controller
//由於我有帶參數,會自動變成POST,所以記得加HttpPost
[HttpPost]
public ActionResult EditPrice(string price, string productID)
{
//利用ProductID抓出該筆資料
var product=db.Products.Where(p => p.ProductID == Convert.ToInt32(productID)).FirstOrDefault();
//這邊將傳入的價格去做更新
if(product!=null){
product.UnitPrice=Convert.ToDecimal(price);
db.SubmitChanges();
}
//直接返回傳入價格
return Content(price);
}
寫到這邊,當按下編輯,並在input中改變價格後按下確定,就會將新的價格更新到資料庫內
而且不會PostBack,對使用者的感覺比較好
剩下就是把取消按鈕做完就完成啦
取消就是把一切回復原狀而已
function returnCancel(data) {
//將編輯連結顯示
$(data).parent().prev().css("display", "");
//抓父父的tr
var pricetd = $(data).parent().parent().parent("tr");
//第4個td
var s = pricetd.children("td").eq(3);
//將input的val放到td裡面
var price = s.children("input").val();
s.html(price );
//將確定跟取消移除
$("#SumitOrCancel").remove();
}
當按下取消之後,就會回復原狀,並不會儲存資料。
寫到這邊,還有兩個美中不足的地方
第一個就是當使用者已經更改價格的欄位但卻按取消時,顯示出來的價格是更改後的價格
但其實因為資料沒有寫入資料庫,因此重整之後會回復成原來的值。
好一點的做法應該要再按下編輯時先將text()存在某個地方,當按下取消時就拿這個值來用就不會錯了
第二個是按使用者連續按了好幾列的編輯,卻沒有按確定或取消,因為我有抓一個span的id
當多次按的時候,id就會重複,因此會出現錯誤
一種改法是當按下某一列的編輯時,其他列的編輯就不能按
另一種將id加入ProductID,使id不會重覆,就不會有錯了。
雖然這邊只去更改了一個欄位,但其實用這種方法可也一次改多個欄位
或是input text 想改成 radiobutton或 select 都沒問題
雖然比起用GridView累了不少,但其實滿好玩的。
此外,由於我的selected還不熟練,因此寫的滿累贅的,應該可以在精簡才是。