8.4 购物车控制器
购物车控制器中主要实现三个处理:将书籍加入购物车,将书籍从购物车中删除,查阅购物车中书籍信息。它主要使用我们刚才创建的三个类:ShoppingCartViewModel类、ShoppingCartRemoveViewModel类与ShoppingCart类。与Store控制器与StoreManager控制器一样,我们需要添加引用一个BookStoreEntities对象。
追加一个ShoppingCart控制器,保持“为‘创建’、‘更新’、‘删除’和‘详细信息’方案添加操作方法”复选框为非选取状态,如图8-3所示。
图8-3 添加ShoppingCart控制器
完整的ShoppingCart控制器中的代码如代码清单8-6所示。Index方法与Add方法看起来非常相似。RemoveFromCart方法与CartSummary方法中使用了两个特殊的类,我们将在下一节中针对这两个类做一详细介绍。
代码清单8-6 完整的ShoppingCart控制器中的代码
using System.Linq;
using System.Web.Mvc;
using MvcBookStore.Models;
using MvcBookStore.ViewModels;
namespace MvcBookStore.Controllers
{
public class ShoppingCartController : Controller
{
BookStoreEntities storeDB = new BookStoreEntities();
//
// GET: /ShoppingCart/
public ActionResult Index()
{
var cart = ShoppingCart.GetCart(this.HttpContext);
//创建我们的视图模型
var viewModel = new ShoppingCartViewModel
{
CartItems = cart.GetCartItems(),
CartTotal = cart.GetTotal()
};
// 返回视图
return View(viewModel);
}
//
// GET: /Store/AddToCart/5
public ActionResult AddToCart(int id)
{
// 从数据库中获取书籍信息
var addedBook = storeDB.Books
.Single(book => book.Id == id);
// 将这本书加入购物车
var cart = ShoppingCart.GetCart(this.HttpContext);
cart.AddToCart(addedBook);
//返回页面继续购物
return RedirectToAction("Index");
}
//
// AJAX: /ShoppingCart/RemoveFromCart/5
[HttpPost]
public ActionResult RemoveFromCart(int id)
{
// 从购物车中删除书籍
var cart = ShoppingCart.GetCart(this.HttpContext);
// 取得书名以便在确认信息中显示
string bookName = storeDB.Carts
.Single(item => item.RecordId == id).Book.Title;
// 从购物车中删除
int itemCount = cart.RemoveFromCart(id);
// 显示确认信息
var results = new ShoppingCartRemoveViewModel
{
Message = Server.HtmlEncode(bookName) +" 已经从购物车中被删除。",
CartTotal = cart.GetTotal(),
CartCount = cart.GetCount(),
ItemCount = itemCount,
DeleteId = id
};
return Json(results);
}
//
// GET: /ShoppingCart/CartSummary
[ChildActionOnly]
public ActionResult CartSummary()
{
var cart = ShoppingCart.GetCart(this.HttpContext);
ViewData["CartCount"] = cart.GetCount();
return PartialView("CartSummary");
}
}
}
8.5 使用Ajax.ActionLink处理Ajax更新
接下来,我们将使用ShoppingCartViewModel视图模型,采取同样的方法创建一个购物车使用的主视图以及一个列表视图,如图8-4所示。
图8-4 创建购物车用主视图
但是,在从购物车中删除书籍的时候,我们不使用Html.ActionLink,而是使用如下所示的Ajax.ActionLink。
@Ajax.ActionLink("Remove from cart","RemoveFromCart",new { id = item.RecordId },
new AjaxOptions { OnSuccess = "handleUpdate"})
这个方法的执行结果与Html.ActionLink帮助器的执行结果非常类似,但是它并不提交表单,而是向我们的RemoveFromCart方法执行 一个AJAX回调,返回一个序列化的JSON对象的,该对象将被自动传入到页面中一个可选的OnSuccess参数所指定的方法—本例中为 handleUpdate方法中。在handleUpdate这个JavaScript方法中解析JSON对象,使用Jquery来对视图执行以下四个快 速更新操作。
- 从列表中移除被删除的书籍。
- 更新购物车中的书籍数量。
- 向用户显示更新信息。
- 更新购物车中的总金额。
因为书籍删除操作已经在主页面中使用一个Ajax回调操作被处理过了,所以我们不需要再额外为了RemoveFromCart(删除书籍)方法而添加一个视图了。主页面中的代码如代码清单8-7中所示。
代码清单8-7 购物车页面中的代码
@model MvcBookStore.ViewModels.ShoppingCartViewModel
@{
ViewBag.Title = "购物车";
}
<script src="/Scripts/jquery- 1.4.4.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
// 页面打开时在点击链接的时候执行删除操作
$(".RemoveLink").click(function () {
//取得链接中的ID
var recordToDelete = $(this).attr("data-id");
if (recordToDelete != '') {
// 执行ajax调用
$.post("/ShoppingCart/RemoveFromCart", { "id":recordToDelete },
function (data) {
// 删除成功时执行的代码
// 更新页面元素
if (data.ItemCount == 0) {
$('#row-' + data.DeleteId).fadeOut('slow');
} else {
$('#item-count-' +data.DeleteId).text(data.ItemCount);
}
$('#cart-total').text(data.CartTotal);
$('#update-message').text(data.Message);
$('#cart-status').text('Cart (' + data.CartCount + ')');
});
}
});
});
function handleUpdate() {
//装载并解析JSON对象
var json = context.get_data();
var data = Sys.Serialization.JavaScriptSerializer.deserialize(json);
// 更新页面元素
if (data.ItemCount == 0) {
$('#row-' + data.DeleteId).fadeOut('slow');
} else {
$('#item-count-' + data.DeleteId).text(data.ItemCount);
}
$('#cart-total').text(data.CartTotal);
$('#update-message').text(data.Message);
$('#cart-status').text('Cart (' + data.CartCount + ')');
}
</script>
<h3>
<em>查阅</em> 购物车
</h3>
<p>
@Html.ActionLink("结算", "AddressAndPayment", "Checkout")
</p>
<div id="update-message">
</div>
<table>
<tr>
<th>
书名
</th>
<th>
单价
</th>
<th>
数量
</th>
<th></th>
</tr>
@foreach (var item in Model.CartItems)
{
<tr id="row-@item.RecordId">
<td>
@Html.ActionLink(item.Book.Title,"Details", "Store", new { id = item.BookId },
null)
</td>
<td>
@item.Book.Price
</td>
<td id="item-count-@item.RecordId">
@item.Count
</td>
<td>
<a href="#" class="RemoveLink" data-id="@item.RecordId">删除书籍</a>
</td>
</tr>
}
<tr>
<td>
总金额
</td>
<td>
</td>
<td>
</td>
<td id="cart-total">
@Model.CartTotal
</td>
</tr>
</table>
为了进行测试,让我们更新一下Store控制器中的书籍详细信息(Details)视图中的代码,添加一个“放入购物车”按钮。同时,添加一些书籍的种类,作者,单价信息。更新后的代码如代码清单8-8所示。
代码清单8-8 修改后的书籍详细信息视图中的代码
@model MvcBookStore.Models.Book
@{
ViewBag.Title = "书籍 - " + Model.Title;
}
<h2>@Model.Title</h2>
<div id="book-details">
<p>
<em>种类:</em>
@Model.Genre.Name
</p>
<p>
<em>作者:</em>
@Model.Author.Name
</p>
<p>
<em>单价:</em>
@String.Format("{0:F}",Model.Price)
</p>
<p>
@Html.ActionLink("放入购物车", "AddToCart", "ShoppingCart",
new { id = Model.Id }, "")
</p>
</div>
现在我们可以通过Store控制器来测试将书籍放入购物车及从购物车中删除书籍的操作。运行应用程序,访问Store控制器的主页面,如图8-5所示。
图8-5 Store控制器的主页面
接下来,点击一个种类来查看该书籍种类中的书籍列表,如图8-6所示。
图8-6 书籍列表页面
点击一本书名,显示我们修改后的书籍详细信息页面,然后点击“放入购物车”链接,如图8-7所示。
图8-7 书籍详细信息页面
点击按钮后浏览器显示购物车页面,如图8-8所示。
图8-8 购物车页面
点击“删除书籍”链接,查看使用Ajax删除书籍的运行结果,如图8-9所示。
图8-9点击“删除书籍”链接后书籍被删除
现在我们已经建立了一个购物车页面,允许匿名用户将书籍放入购物车中。在下一节中,我们将允许注册用户完成本次购买的下订单过程。