SportsStore是《精通ASP.NET MVC3框架(第三版)》中演示的MVC專案,在該專案中涵蓋了MVC的眾多方面,包括:使用DI容器、URL優化、導航、分頁、購物車、訂單、產品管理、影象上傳......是不錯的MVC實踐專案,但該專案不是放在多層框架下開發的,離真實專案還有一段距離。本系列將嘗試在多層框架下實現SportsStore專案,並用自己的方式實現一些功能。
本篇為"在三層架構下實現SportsStore"系列的第十一篇,包括:
■ 13、使用Knockout實現增刪改查
□ 13.1 關於Knockout
□ 13.2 實現增刪改查
13、使用Knockout實現增刪改查
13.1 關於Knockout
在ASP.NET MVC中,拿一個強型別檢視頁來說,檢視View和Model有著比較強的耦合。Knockout的出現就是為了解耦View和Model。Knockout是一個Javascript庫,他通過建立View Model,實現了View和Model之間的解耦,這符合基於UI的設計模式"MVVM":
● Model: 應用程式的領域模型(Domain Model),在Knockout中,經常使用Ajax對領域模型進行讀寫。
● View: 動態顯示或更新View Model的UI
● View Model: 在UI層的JavaScript物件,UI層的Model。
關於Knockout,請參考官網。http://knockoutjs.com/index.html
13.2 實現增刪改查
在ProductManage控制器中實現增刪改查的邏輯:
using System.Linq; using System.Web.Mvc; using MySportsStore.IBLL; using MySportsStore.Model; using Ninject; namespace MySportsStore.WebUI.Controllers { public class ProductManageController : BaseController { [Inject] public IProductService ProductService { get; set; } public ProductManageController() { this.AddDisposableObject(ProductService); } public ActionResult Index() { return View(); } public JsonResult GetProducts() { return Json(ProductService.LoadEntities(p => true), JsonRequestBehavior.AllowGet); } public JsonResult AddProduct(Product product) { ProductService.AddEntity(product); return Json(product, JsonRequestBehavior.AllowGet); } public JsonResult EditProduct(Product product) { ProductService.UpdateEntity(product); return Json(ProductService.LoadEntities(p => true), JsonRequestBehavior.AllowGet); } public JsonResult DeleteProduct(int id) { var dbProduct = ProductService.LoadEntities(p => p.Id == id).FirstOrDefault(); if (ProductService.DeleteEntity(dbProduct) > 0) { return Json(new {msg = true},JsonRequestBehavior.AllowGet); } return Json(new { msg = false }, JsonRequestBehavior.AllowGet); } } }
在ProductManage/Index.cshtml檢視中:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> <style type="text/css"> //省去樣式 </style> <script src="~/Scripts/jquery-1.8.2.min.js"></script> <script src="~/Scripts/knockout-3.1.0.js"></script> <script type="text/javascript"> $(function() { var viewModel = new ProductViewModel(); ko.applyBindings(viewModel); }); function ProductViewModel() { var self = this; //讓屬性observalbe self.Id = ko.observable(""); self.Name = ko.observable(""); self.Description = ko.observable(""); self.Price = ko.observable(""); self.Category = ko.observable(""); var Product = { Id: self.Id, Name: self.Name, Description: self.Description, Price: self.Price, Category: self.Category }; self.Product = ko.observable(); self.Products = ko.observableArray(); //初始化產品列表 $.ajax({ url: '@Url.Action("GetProducts","ProductManage")', cache: false, type: 'GET', contentType: 'application/json; charset=utf-8', data: {}, success: function(data) { self.Products(data); } }); //初始化之後計算總價,增加一個計算屬性 self.Total = ko.computed(function() { var sum = 0; var arr = self.Products(); for (var i = 0; i < arr.length; i++) { sum += arr[i].Price; } return sum; }); //新增 self.create = function() { if (Product.Name() != "" && Product.Price() != "" && Product.Description() != "" && Product.Category() != "") { $.ajax({ url: '@Url.Action("AddProduct","ProductManage")', cache: false, type: 'POST', contentType: 'application/json; charset=utf-8', data: ko.toJSON(Product), success: function(data) { self.Products.push(data); //清空 self.Name(""); self.Description(""); self.Price(""); self.Category(""); } }).fail(function(xhr, textStatus, err) { alert(err); }); } else { alert("不能為空~~"); } }; //刪除 self.delete = function(Product) { if (confirm('確定要刪除 "' + Product.Name + '" 嗎')) { //var id = Product.Id; $.ajax({ url: '@Url.Action("DeleteProduct","ProductManage")', cache: false, type: 'GET', contentType: 'application/json; charset=utf-8', //data: ko.toJSON(id), data: {id : Product.Id }, success: function(data) { if (data.msg == true) { self.Products.remove(Product); } else { alert("伺服器內部錯誤~~"); } } }).fail(function(xhr, textStatus, err) { alert("出錯了~~"); }); } }; //顯示更新介面 self.edit = function(Product) { self.Product(Product); }; //更新 self.update = function() { var Product = self.Product(); $.ajax({ url: '@Url.Action("EditProduct","ProductManage")', cache: false, type: 'POST', contentType: 'application/json; charset=utf-8', data: ko.toJSON(Product), success: function(data) { self.Products.removeAll(); self.Products(data); self.Product(null); alert("更新成功~~"); } }); }; //重置 self.reset = function() { self.Name(""); self.Price(""); self.Category(""); self.Description(""); }; //取消產品細節 self.cancel = function() { self.Product(null); }; } //格式化價格 function formatCurrency(value) { return "¥" + value.toFixed(2); } </script> </head> <body> <div id="body"> <h3>產品管理</h3> <table id="products1" data-bind=""> <thead> <tr> <th>編號</th> <th>產品名稱</th> <th>產品描述</th> <th>產品類別</th> <th>價格</th> <th>操作</th> </tr> </thead> <tbody data-bind="foreach: Products"> <tr> <td data-bind="text: Id"></td> <td data-bind="text: Name"></td> <td data-bind="text: Description"></td> <td data-bind="text: Category"></td> <td data-bind="text: formatCurrency(Price)"></td> <td> <button data-bind="click: $root.edit">編輯</button> <button data-bind="click: $root.delete">刪除</button> </td> </tr> </tbody> <tfoot> <tr> <td></td> <td></td> <td></td> <td>總計:</td> <td data-bind="text: formatCurrency($root.Total())"></td> <td></td> </tr> </tfoot> </table> <br/> <br/> <div style="border-top: solid 2px #282828; width: 430px; height: 10px"> </div> <div data-bind="if: Product"> <div><h2>更新產品</h2></div> <div> <label for="productId" data-bind="visible: false">編號</label> <label data-bind="text: Product().Id, visible: false"></label> </div> <div> <label for="name">產品名稱</label> <input data-bind="value: Product().Name" type="text" title="Name"/> </div> <div> <label for="description">產品描述</label> <input data-bind="value: Product().Description" type="text" title="Description"/> </div> <div> <label for="category">產品類別</label> <input data-bind="value: Product().Category" type="text" title="Category"/> </div> <div> <label for="price">產品價格</label> <input data-bind="value: Product().Price" type="text" title="Price"/> </div> <br/> <div> <button data-bind="click: $root.update">更新</button> <button data-bind="click: $root.cancel">取消</button> </div> </div> <div data-bind="ifnot: Product()"> <div> <h2>新增產品</h2> </div> <div> <label for="name">產品名稱</label> <input data-bind="value: $root.Name" type="text" title="Name" /> </div> <div> <label for="description">產品描述</label> <input data-bind="value: $root.Description" type="text" title="Description" /> </div> <div> <label for="category">產品類別</label> <input data-bind="value: $root.Category" type="text" title="Category" /> </div> <div> <label for="price">產品價格</label> <input data-bind="value: $root.Price" type="text" title="Price" /> </div> <div> <button data-bind="click: $root.create">新增</button> <button data-bind="click: $root.reset">重置</button> </div> </div> </div> </body> </html>
原始碼在這裡。
“MVC專案實踐,在三層架構下實現SportsStore”系列包括: