用jQuery在MVC上做類似GridView的編輯效果

用jQuery在MVC上做類似GridView的編輯效果

在MVC上開發由於缺少了Control的幫助,因此很多東西必須要手動完成。

但這也讓我體會到jQuery有趣的地方,今天來練習用jQuery做出類似GirdView在編輯資料時的效果。

 

首先還是先利用北風資料庫撈出一些產品資料來用

 

da43e5a7a5144b96901f97779ee4cdb3

 

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事件
}

寫完之後,當按下編輯按鈕時,畫面就會從原先的

 

34135bbb1884455a9a759f8425bbef41

變成,

8e7e299bd2004b558f1970659fd2d351

這樣,接著繼續來寫按下確定之後,利用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還不熟練,因此寫的滿累贅的,應該可以在精簡才是。