MVC项目实践,在三层架构下实现SportsStore-11,使用Knockout实现增删改查
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”系列包括:
MVC项目实践,在三层架构下实现SportsStore,从类图看三层架构
MVC项目实践,在三层架构下实现SportsStore-01,EF Code First建模、DAL层等
MVC项目实践,在三层架构下实现SportsStore-02,DbSession层、BLL层
MVC项目实践,在三层架构下实现SportsStore-03,Ninject控制器工厂等
MVC项目实践,在三层架构下实现SportsStore-04,实现分页
MVC项目实践,在三层架构下实现SportsStore-05,实现导航
MVC项目实践,在三层架构下实现SportsStore-06,实现购物车
MVC项目实践,在三层架构下实现SportsStore-07,实现订单提交
MVC项目实践,在三层架构下实现SportsStore-08,部署到IIS服务器
MVC项目实践,在三层架构下实现SportsStore-09,ASP.NET MVC调用ASP.NET Web API的查询服务
MVC项目实践,在三层架构下实现SportsStore-10,连接字符串的加密和解密
MVC项目实践,在三层架构下实现SportsStore-11,使用Knockout实现增删改查
MVC项目实践,在三层架构下实现SportsStore-11,使用Knockout实现增删改查的更多相关文章
- MVC项目实践,在三层架构下实现SportsStore,从类图看三层架构
在"MVC项目实践,在三层架构下实现SportsStore-02,DbSession层.BLL层"一文的评论中,博友浪花一朵朵建议用类图来理解本项目的三层架构.于是就有了本篇: I ...
- MVC项目实践,在三层架构下实现SportsStore-02,DbSession层、BLL层
SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管 ...
- MVC项目实践,在三层架构下实现SportsStore-01,EF Code First建模、DAL层等
SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管 ...
- MVC项目实践,在三层架构下实现SportsStore-03,Ninject控制器工厂等
SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管 ...
- MVC项目实践,在三层架构下实现SportsStore-04,实现分页
SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管 ...
- MVC项目实践,在三层架构下实现SportsStore-05,实现导航
SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管 ...
- MVC项目实践,在三层架构下实现SportsStore-06,实现购物车
SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管 ...
- MVC项目实践,在三层架构下实现SportsStore-07,实现订单提交
SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管 ...
- MVC项目实践,在三层架构下实现SportsStore-08,部署到IIS服务器
SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管 ...
- MVC项目实践,在三层架构下实现SportsStore-09,ASP.NET MVC调用ASP.NET Web API的查询服务
ASP.NET Web API和WCF都体现了REST软件架构风格.在REST中,把一切数据视为资源,所以也是一种面向资源的架构风格.所有的资源都可以通过URI来唯一标识,通过对资源的HTTP操作(G ...
随机推荐
- Eclipse中打包maven项目-war包方式
IntelliJ IDEA打包成war(包括maven项目)点击打开链接 首先要在maven项目中的pom.XML中配置好需要的配置: <project xmlns="http://m ...
- day8--socket回顾
后面学习了线程.协成和异步,它们的框架都是基于socket的协议,基本原理都是一样的,现在把这几个模块重温一下,尽量掌握这些知识更全面一些. 动态导入模块,知道知道模块名,可以像反射一样,使用字符串来 ...
- Educational Codeforces Round 26-D. Round Subset
题目大意:给你n个数字(小于1e18),从n个数中取k个数字相乘,使其后缀0最多,问你后缀0最多是多少. 知道得用三维的dp[ i ] [ j ] [ k ] 第一维表示用到第 i 个数为止,j 表 ...
- Docker 容器中无ss命令解决方法
在早期运维工作中,查看服务器连接数一般都会用netstat命令.其实,有一个命令比netstat更高效,那就是ss(Socket Statistics)命令!ss命令可以用来获取socket统计信息, ...
- BZOJ1040 [ZJOI2008]骑士 基环树林(环套树) 树形动态规划
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题意概括 有n个人,每一个人有一个最恨的人. 并且,每一个人有一个权值. 一个人不可以和他最恨的人同时被选中. 现在请你求出在 ...
- MSF《构建之法》阅读笔记5
第七章 MSF MSF是一种软件开发方法,MSF原则包括1推动信息共享和沟通,2为共同的远景而工作,3充分授权和信任,4各司其职,对项目共同负责,5交付增量的价值,6保持敏捷,预期和适应变化,7投资质 ...
- unity pattern not found
在之前破解成功再次破解或者电脑上多个版本Unity往往会导致破解失败. 破解失败解决方法如下: 先用破解软件破解,虽然是破解失败但是还是可以在破解的目录下找到那个ulf文件. 这时候直接打开unity ...
- 001.Keepalived简介
一 Keepalived 定义 Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案,可以解决静态路由出现的单点故障问题.一个LVS服务会有2台服务器运行Keepalived,一台 ...
- flask 模板block super()的讲解
Flask强大的地方就可以引用模板,而且非常方便. 这里不得不介绍block这个概念. 模板的文件一般放在templates文件夹下,我们这里新建一个HTML文件,存放模板,'base.html' 在 ...
- CKEditor 4.4.1 添加代码高亮显示插件功能--使用官方推荐Code Snippet插件
随着CKEditor4.4.1的发布,以前一直困扰的代码高亮问题终于完美的得到解决,在CKEditor4.4中官方发布了Code Snippet这个代码片段的插件,终于可以完美的内嵌使用代码高亮了,以 ...