NodeJS+Angular+Mongodb Web开发(2)
来源:互联网 发布:c语言带小数点数字求和 编辑:程序博客网 时间:2024/06/04 18:44
1. 项目简介
本项目提供了实现一个购物车的实际例子,允许你添加、删除物品,经历结账过程,查看订单等,这个例子可以让你了解在结账过程中,如何利用AngularJS在视图之间进行切换。
本项目创建的购物车提供了所需的大部分功能,但是省略了诸如身份验证和错误处理等细节,只是单纯地设计到与购物车有关的东西,其余一概省略。
例如本例子采用一个userid(用户ID)被硬编码为customerA的用户,所以不太可能直接用于生产,除非你在此基础上花费不小的功夫继续扩展。
2. 基本流程
本实例的一般逻辑流程如下:
3. 用到的库
- express:作为项目的主web服务器
- body-parser:为post请求提供JSON正文支持
- ejs:用于呈现HTML模板
- mongodb:用于访问MongoDB数据库
- mongoose:用于提供结构化的数据模型
- AngularJs库
4. 项目的目录结构
5. 定义模式
需要一个顾客模型作为购物车的容器,需要被放入购物车的产品,结账时需要账单信息和发货信息,下订单时,需要存储订单。
基于以上,设计模式。
(1)定义地址模式地址模式是通用的,既可以用在发货信息,也可以用在账单信息,包含标准地址信息。(2)定义账单模式包含标准信用卡数据(信用卡类型、账户名、账户号、过期时间、地址)(3)定义产品模式包含name、imagefile、description、price、instock(存货数量)(4)定义数量模式存储产品的数量(5)定义订单模式包含订购的五品、发货信息、账单信息(6)定义顾客模式包括标准的身份信息
//cart_model.jsvar mongoose=require('mongoose');var Schema=mongoose.Schema;//定义地址模式var AddressSchema=new Schema({ name:String, address:String, city:String, state:String, zip:String},{_id:false});mongoose.model('Address',AddressSchema);//定义账单模式var BillingSchema=new Schema({ cardtype:{type:String,enum:['Visa','MasterCard','Amex']}, name:String, number:String, expiremonth:Number, expireyear:Number, address:[AddressSchema]},{_id:false});mongoose.model('Billing',BillingSchema);//定义产品模式var ProductSchema=new Schema({ name:String, imagefile:String, description:String, price:Number, instock:Number});mongoose.model('Product',ProductSchema);//定义产品数量模式var ProductQuantitySchema=new Schema({ quantity:Number, product:[ProductSchema]},{_id:false});mongoose.model('ProductQuantity',ProductQuantitySchema);//定义订单模式var OrderSchema=new Schema({ userid:String, items:[ProductQuantitySchema], shipping:[AddressSchema], billing:[BillingSchema], status:{type:Date,default:Date.now}});mongoose.model('Order',OrderSchema);//定义顾客模式var Customer=new Schema({ userid:{type:String,unique:true,required:true}, shipping:[AddressSchema], billing:[BillingSchema], cart:[ProductQuantitySchema]});mongoose.model('Customer',Customer);
6. 创建购物车服务器
代码很简单,如下:
var express=require('express');var bodyParser=require('body-parser');var mongoose=require('mongoose');var url='mongodb://localhost:27017/cart';var db=mongoose.connect(url);mongoose.Promise = global.Promise;require('./models/cart_model.js');var app=express();app.engine('.html',require('ejs').__express);app.set('views',__dirname+'/views');app.set('view engine','html');app.use(bodyParser.urlencoded({extended:false}));require('./cart_routes')(app);app.listen(3000);console.log('App running...');
7. 实现路由,以支持产品、购物车和订单请求
商品、订单和顾客的路由
//cart_routes.jsvar express=require('express');module.exports=function(app){ //加载控制器 var customers=require('./controllers/customers_controller'); var products=require('./controllers/product_controller'); var orders=require('./controllers/orders_controller'); //配置中间件 app.use('/static',express.static('./static')); app.use('/images',express.static('./images')); app.use('/lib',express.static('./lib')); //配置路由 app.get('/',function(req,res){ res.render('shopping'); }); //商品 app.get('/products/get',products.getProducts); //订单 app.get('/orders/get',orders.getOrders); app.post('/orders/add',orders.addOrder); //顾客 app.get('customers/get',customers.getCustomers); app.post('customers/update/shipping',customers.updateShipping); app.post('customers/update/billing',customers.updateBilling); app.post('customers/update/cart',customers.updateCart);};
8. 实现基于模型的控制器路由
(1)实现产品模型控制器
getProduct()
:根据在查询中包含的productId
查找单个产品
getProducts()
:查找所有产品
如果查询成功,则返回JSON字符串,请求时便则返回404错误。
//product_controller.jsvar mongoose=require('mongoose');var Product=mongoose.model('Product');exports.getProduct=function(req,res){ Product.findOne({_id:req.query.productId}) .exec(function(err,product){ if(err){ throw err; } if(!product){ res.json(404,{msg:'Product Not Found!'}); }else{ res.json(product); } });};exports.getProducts=function(req,res){ Product.find() .exec(function(err,products){ if(err){ throw err; } if(!products){ res.json(404,{msg:'Products Not Found!'}); }else{ res.json(products); } });};
(2)实现订单模型控制器
getOrder()
:根据查询中包含的orderId
查找一个订单
getOrders()
:查找属于当前用户的所有订单
addOrder()
:通过获取POST请求的updateShipping updateBilling OrderItems
三个参数建立一个新的Order对象。
如果订单成功保存,则将购物车cart清空。
在这个例子中, userid
是硬编码的customerA
。
//orders_controller.jsvar mongoose=require('mongoose');var Customer=mongoose.model('Customer');var Order=mongoose.model('Order');var Address=mongoose.model('Address');var Billing=mongoose.model('Billing');//根据订单编号查找订单orderexports.getOrder=function(req,res){ Order.findOne({_id:req.query.orderId}) .exec(function(err,order){ if(err){ throw err; } if(!order){ res.json(404,{msg:'Order Not Found!'}); }else{ res.json(order); } });};//查找当前用户名下所属的所有订单ordersexports.getOrders=function(req,res){ Order.find({userid:'customerA'}) .exec(function(err,orders){ if(err){ throw err; } if(!orders){ res.json(404,{msg:'Orders Not Found!'}); }else{ res.json(orders); } });};//exports.getOrder=function(req,res){ Order.findOne({_id:req.query.orderId}) .exec(function(err,order){ if(err){ throw err; } if(!order){ res.json(404,{msg:'Order Not Found!'}); }else{ res.json(order); } });};//添加订单信息exports.addOrder=function(req,res){ var orderShipping=new Address(req.body.updateShipping); var orderBilling=new Billing(req.body.updateBilling); var orderItems=req.body.orderItems; var newOrder=new Order({ userid:'customerA', items:orderItems, shipping:orderShipping, billing:orderBilling, }); newOrder.save(function(err,results){ if(err){ res.json(500,'Failed to save Order!'); }else{ //保存到订单成功后,清空购物车 Customer.update({userid:'customerA'},{$set:{cart:[]}}) .exec(function(err,results){ if(err||results<1){ res.json(404,{msg:'Failed to update Cart!'}); }else{ res.json({msg:'Order Saved!'}); } }); } });};
(3)实现顾客模型控制器
getCustomer()
:查找当前顾客的有关信息
updateShipping()
通过Post请求的updateShipping
参数创建新的Address对象,然后使用一个update()
方法来使用新的发货数据来更新Customer
对象
updateBilling()
:通过Post请求的updateBilling
参数创建新的Billing
对象,然后使用一个update()
方法来使用新的账单数据来更新Customer
对象
updateCart()
通过Post请求的updateCart
参数来更新Customer对象的cart字段。
//customers_controller.jsvar mongoose=require('mongoose');var Customer=mongoose.model('Customer');var Address=mongoose.model('Address');var Billing=mongoose.model('Billing');//查找当前顾客的有关信息exports.getCustomer=function(req,res){ Customer.findOne({userid:'customerA'}) .exec(function(err,customer){ if(err){ throw err; } if(!customer){ res.json(404,{msg:'Customer Not Found!'}); }else{ res.json(customer); } });};//更新发货信息exports.updateShipping=function(req,res){ var newShipping=new Address(req.body.updateShipping); Customer.update({userid:'customerA'},{$set:{shipping:[newShipping.toObject()]}}) .exec(function(err,results){ if(err||results<1){ res.json(404,{msg:'Failed to update Shipping!'}); }else{ res.json({msg:'Customer Shipping Updated!'}); } });};//更新支付信息exports.updateBilling=function(req,res){ //你可以在此验证信用卡信息,并在信用卡无效时取消结账 var newBilling=new Billing(req.body.updateBilling); Customer.update({userid:'customerA'},{$set:{billing:[newBilling.toObject()]}}) .exec(function(err,results){ if(err||results<1){ res.json(404,{msg:'Failed to update Billing!'}); }else{ res.json({msg:'Customer Billing Updated!'}); } });};//更新购物车exports.updateCart=function(req,res){ Customer.update({userid:'customerA'},{$set:{cart:req.body.updateCart}}) .exec(function(err,results){ if(err||results<1){ res.json(404,{msg:'Failed to update Cart!'}); }else{ res.json({msg:'Customer Cart Updated!'}); } });};
9. 实现购物车和结账视图
shopping.html
主视图以及购物车(cart)、发货(shipping)、账单(billing)、复核(review)和订单(orders)页面的不同的局部视图。
(1) 实现购物视图
该视图是购物应用程序的主视图,注册了Angular应用程序myapp
,并通过shoppingController
控制器进行控制。
<!--shopping.html--><!DOCTYPE html><html lang="en" ng-app='myApp'><head> <meta charset="UTF-8"> <title>Shopping Cart</title> <link rel="stylesheet" type="text/css" href="/static/css/bootstrap.min.css" /> <link rel="stylesheet" type="text/css" href="/static/css/cart_styles.css" /></head><body> <div class="container" ng-controller='shoppingController'> <div class="navbar navbar-default navbar-fixed-top"> <h1 class="navbar-header">My Store</h1> <div class="navbar-text navbar-right" id='bar'> <span class="navbar-link" id="cartLink" ng-click='setContent("cart.html")'> {{customer.cart.length?customer.cart.length:0}} items </span> <img src="/images/cart.png" alt="image" /> <span> | </span> <span class="navbar-link orders" ng-click='setContent("orders.html")'>Orders</span> </div> </div> <div id='main'> <div ng-include='content'></div> </div> </div> <script src="/static/js/angular.min.js"></script> <script src="/static/js/cart_app.js"></script></body></html>
效果如下:
(2) 实现所有产品列表视图
向用户提供可供选择的产品列表
使用productsController
控制器上的ng-repeat
列出产品
当点击<img>
元素时,setProduct()
函数在控制器中被调用,该函数设置当前$scope.product
值,并把$scope.content
值更改为product.html
<!--products.html--><div id="productsContainer" class="row"> <div class='col-sm-6 col-md-4'> <div class="listItem" ng-repeat='product in products'> <a href="#" class="thumbnail"><img class="listImg" ng-click='setProduct(product_.id)' ng-src='../images/{{product.imagefile}}' /></a> <div class="caption"> <span class='prodName btn btn-default' ng-click='setProduct(product_.id)'>{{product.name}}</span> <span class='price btn btn-primary'>{{product.price | currency}}</span> </div> </div> </div></div>
效果如下:
(3) 实现产品详细页面视图
这里使用访问$scope.product
值的AngularJS表达式来显示产品信息,Add to Cart
按钮把当前产品product._id
发送到控制器的addToCart()
函数。
//product.html<div id="productContainer"> <img class="fullImg" ng-src='../images/{{product.imagefile}}' /> <div class="prodInfo"> <p class="itemTitle">{{product.name}}</p> <p class="prodDesc">{{product.description}}</p> <p class="fullPrice">{{product.price | currency}}</p> <p class="status">{{product.instock}}</p> <p class="cartButton" ng-click='addToCart(product._id)'>Add To Cart</p> <img src="../images/cart.png" /> </div></div>
效果如下:
(4) 实现购物车视图
一旦用户单击了Add To Cart
按钮,物品就被添加到购物车中,并且视图更改为购物车视图。
<!--cart.html--><div id="cartsContainer" class="row"> <div class="col-sm-6 col md-4"> <div class="listItem thumbnail" ng-repeat="item in customer.cart" ng-init="product=item.product[0]"> <img class="listImg" ng-click="setProduct(product._id)" ng-src="../images/{{product.imagefile}}" /> <span class="prodName">{{product.name}}</span> <span > <span class="price">{{product.price|currency}}</span> <input class="quantity" type="text" ng-model="item.quantity" /> <label class="quantity">Quantity</label> <span class="delete" ng-click="deleteFromCart(product._id)">Remove</span> </span> </div> </div> <hr> <div> <span>Shipping</span> <span class="price">{{shipping|currency}}</span> </div> <hr> <div> <span>Total</span> <span class="price">{{cartTotal()|currency}}</span> </div> <hr> <div> <div class="cc"> <span class="button btn btn-success" ng-click="checkout()" ng-hide="customer.cart.length==0"> Checkout </span> <span class="button btn btn-primary" ng-click="setContent('products.html')"> Continue Shopping </span> </div> </div></div>
效果如下:
(5) 实现发货视图
当用户单击购物车中的Checkout
按钮时,就显示发货视图,允许用户在此输入发货信息
<!--shipping.html--><div id="shippingContainer" role='form'> <h2>Ship To:</h2> <div class="form-group"> <label for='shipname'>Name</label> <input id='shipname' type="text" ng-model="customer.shipping[0].name" /><br> </div> <div class="form-group"> <label for=''>Address</label> <input type="text" ng-model="customer.shipping[0].address" /><br> </div> <div class="form-group"> <label for=''>City</label> <input type="text" ng-model="customer.shipping[0].city" /><br> </div> <div class="form-group"> <label for=''>State</label> <input type="text" ng-model="customer.shipping[0].state" /><br> </div> <div class="form-group"> <label for=''>Zipcode</label> <input type="text" ng-model="customer.shipping[0].zip" /> </div> <hr> <div class='row'> <span class="button btn btn-success" ng-click="setShipping()"> Continue to Billing </span> <span class="button btn btn-primary" ng-click="setContent('products.html')"> Continue Shopping </span> </div></div>
效果如下:
(6) 实现账单视图
当用户在发货视图单击Continue to Billing
按钮时,显示账单视图,允许用户输入账单信息。
<!--billing.html--><div id="shippingContainer"> <h2>Card Info: </h2> <label>Card</label> <input type="radio" ng-model="customer.billing[0].cardtype" value="Visa"> Visa <input type="radio" ng-model="customer.billing[0].cardtype" value="Amex"> Amex <input type="radio" ng-model="customer.billing[0].cardtype" value="MasterCard"> MasterCard <br><label>Name on Card</label> <input type="text" ng-model="customer.billing[0].name" /> <br><label>Card Number</label> <input type="text" ng-model="customer.billing[0].number" /> <br><label>Expires</label> <select ng-model="customer.billing[0].expiremonth" ng-options="m for m in months"></select> <select ng-model="customer.billing[0].expireyear" ng-options="m for m in years"></select> <label>Card CCV</label> <input class="security" type=text ng-model="ccv" /> <h2>Billing Address:</h2> <label>Name</label> <input type="text" ng-model="customer.billing[0].address[0].name" /> <br><label>Address</label> <input type="text" ng-model="customer.billing[0].address[0].address" /> <br><label>City</label> <input type="text" ng-model="customer.billing[0].address[0].city" /> <br><label>State</label> <input type="text" ng-model="customer.billing[0].address[0].state" /> <br><label>Zipcode</label> <input type="text" ng-model="customer.billing[0].address[0].zip" /> <hr> <div> <span class="button btn btn-success" ng-click="verifyBilling(ccv)"> Verify Billing </span> <span class="button btn btn-primary" ng-click="setContent('products.html')"> Continue Shopping </span> </div></div>
效果如下:
(7) 实现复核视图
当用户单击账单视图中的Verify Billing
按钮时,显示复核按钮,用户可以在此查看订单,包括发货和账单信息。
当顾客点击Make Purchase
按钮时,这些信息被发送到服务器,并创建一个新的订单对象,该视图切换到订单视图。
<!--review.html--><div id="reviewContainer" class='raw'> <div class="col-sm-6 col-md-4"> <div class="listItem thumbnail" ng-repeat="item in customer.cart" ng-init="product=item.product[0]"> <img class="listImg" ng-click="setProduct(product._id)" ng-src="../images/{{product.imagefile}}" /> <div class="caption"> <h3 class="prodName">{{product.name}}</h3> <div> <span class="price label label-danger">Price:{{product.price|currency}}</span> <span class="quantity label label-info">Quantity:{{item.quantity}}</span> </div> <div> <span class="label label-danger">Shipping:{{shipping|currency}}</span> <span class="label label-success">Total:{{cartTotal()|currency}}</span> </div> </div> </div> </div><hr> <div class="twoTable"> <table align="left" class="review list-group"> <tr class='list-group-item'><th>Shipping:</th></tr> <tr class='list-group-item'><td>{{customer.shipping[0].name}}</td></tr> <tr class='list-group-item'><td>{{customer.shipping[0].address}}</td></tr> <tr class='list-group-item'><td>{{customer.shipping[0].city}}</td></tr> <tr class='list-group-item'><td>{{customer.shipping[0].state}}</td></tr> <tr class='list-group-item'><td>{{customer.shipping[0].zip}}</td></tr> </table> <table class="review list-group"> <tr class='list-group-item'><th>Billing:</th></tr> <tr class='list-group-item'><td>{{customer.billing[0].cardtype}} ending in</td></tr> <tr class='list-group-item'><td>{{customer.billing[0].number.slice(-5,-1)}}</td></tr> <tr class='list-group-item'><td>{{customer.billing[0].address[0].name}}</td></tr> <tr class='list-group-item'><td>{{customer.billing[0].address[0].address}}</td></tr> <tr class='list-group-item'><td>{{customer.billing[0].address[0].city}}</td></tr> <tr class='list-group-item'><td>{{customer.billing[0].address[0].state}}</td></tr> <tr class='list-group-item'><td>{{customer.billing[0].address[0].zip}}</td></tr> </table> </div> <div> <span class="button btn btn-success" ng-click="makePurchase()"> Make Purchase </span> <span class="button btn btn-primary" ng-click="setContent('products.html')"> Continue Shopping </span> </div></div>
效果如下:
(8) 实现订单视图
当订单完成时,用户将看到订单视图,显示用户完成的购买。
<!--orders.html--><div id="OrderContainer" class="raw"> <div> <div class="listItem thumbnail" ng-repeat="order in orders"> <div class="caption"> <h2 class="itemTitle">Order: #{{$index+1}}</h2> <p class="prodDesc">Placed: {{order.timestamp|date}}</p> <p class="status">status:{{order.status}}</p> </div><hr> <div class="listItem media" ng-repeat="item in order.items" ng-init="product=item.product[0]"> <span class="media-left"> <img class="listImg " ng-click="setProduct(product._id)" ng-src="../images/{{product.imagefile}}" alt='...' /> </span> <div class="media-body"> <h4 class="media-heading prodName">{{product.name}}</h4> <span> <span class="price">{{product.price|currency}}</span> <label class="quantity">{{item.quantity}}</label> <label class="quantity">Quantity</label> </span> </div> </div> <span class="button btn btn-primary" ng-click="setContent('products.html')"> Continue Shopping </span> </div> </div></div>
效果如下:
10. 实现AngularJS模块和控制器
完成视图后,你需要实现AngularJS控制器代码来支持它们。
可以分解成以下步骤:
- 初始化购物车作用域
$scope.months
和$scope.years
数组填充信用卡表单,$scope.content
决定了在视图中呈现哪个AngularJS部件,它被初始化为products.html
,这样用户就可以开始购物。
- 实现辅助函数
setContent()
函数设置设置$scope.content
值,用以改变视图
cartTotal()
函数遍历用户购物车中的产品,更新$scope.shipping
,并返回一个随后在购物车和复核视图中使用的金额。
- 将物品添加到购物车
当用户点击Add To Cart
按钮时,调用addToCart()
函数,此函数首先遍历customer.cart
中的物品,如果发现已经存在,则增加此物品数量,否则将该物品添加到customer.cart
数组
一旦$scope.customer
被更新,将对/customer/update/cart
路由发出一个$http POST
请求,来更新购物车,通过这种方式,持久化购物车,即使用户关闭浏览器或者离开购物页面也将存在,如果成功该视图切换到cart.html
页面,否则出现一个警告窗口。
- 从购物车删除商品
当用户单击删除Remove
按钮时,调用deleteFromCart()
函数,遍历在customer.cart
中的物品,如果找到则采用array.slice(index,1)
方法数组中删除该物品。
一旦物品被从$scope.customer.cart
删除,对/customer/update/cart
路由执行一个$http POST
请求,来更新购物车,通过这种方式,持久化购物车,即使用户关闭浏览器或者离开购物页面也将存在,如果成功该视图切换到cart.html
页面,否则出现一个警告窗口。
- 结账
当用户在购物车视图单击Checkout
按钮时,调用checkout()
函数,发送带有{updatedCart:$scope.customer.cart}
参数的$http POST
请求来更新购物车。
- 设置发货信息
当用户在购物车视图单击Continue to Billing
按钮时,调用setShipping()
函数,对/customer/update/shipping
路由执行一个$http POST
请求,在post方法中包括参数{updatedShipping:$scopr.customer.shiiping[0]}
,如果请求成功,切换到billing.html
视图,否则出现警告窗口。
- 验证账单
当用户在发货视图单击Verify Billing
按钮时,调用verifyBilling()
函数,信用卡信息可以在这一刻在服务器上进行验证,对/customer/update/billing
路由执行一个$http POST
请求,如果请求成功,切换到review.html
视图,否则出现警告窗口。
- 执行购买
当用户在账单视图单击Make Purchase
按钮时,调用makePurchase()
函数,对/orders/add
路由执行一个$http POST
请求,在post方法中包括orderBilling orderShipping orderItems
参数,如果请求成功,则清空购物车,$scope.customer.cart
被初始化为[]
,新的Order文档将会已经在数据库中创建,因此执行另一个请求,执行/order/get
路由,获取订单的完整列表,然后切换到orders.html
视图。
//cart_app.jsvar app = angular.module('myApp', []);app.controller('shoppingController', ['$scope', '$http', '$window', function($scope, $http, $window) { $scope.months = [1,2,3,4,5,6,7,8,9,10,11,12]; $scope.years = [2014,2015,2016,2017,2018,2019,2020]; $scope.content = '/static/products.html'; $http.get('/products/get') .success(function(data, status, headers, config) { $scope.products = data; $scope.product = data[0]; }) .error(function(data, status, headers, config) { $scope.products = []; }); $http.get('/customers/get') .success(function(data, status, headers, config) { $scope.customer = data; }) .error(function(data, status, headers, config) { $scope.customer = []; }); $http.get('/orders/get') .success(function(data, status, headers, config) { $scope.orders = data; }) .error(function(data, status, headers, config) { $scope.orders = []; }); $scope.setContent = function(filename){ $scope.content = '/static/'+ filename; }; $scope.setProduct = function(productId){ $scope.product = this.product; $scope.content = '/static/product.html'; }; $scope.cartTotal = function(){ var total = 0; for(var i=0; i<$scope.customer.cart.length; i++){ var item = $scope.customer.cart[i]; total += item.quantity * item.product[0].price; } $scope.shipping = total*.05; return total+$scope.shipping; }; $scope.addToCart = function(productId){ var found = false; for(var i=0; i<$scope.customer.cart.length; i++){ var item = $scope.customer.cart[i]; if (item.product[0]._id == productId){ item.quantity += 1; found = true; } } if (!found){ $scope.customer.cart.push({quantity: 1, product: [this.product]}); } $http.post('/customers/update/cart', { updatedCart: $scope.customer.cart }) .success(function(data, status, headers, config) { $scope.content = '/static/cart.html'; }) .error(function(data, status, headers, config) { $window.alert(data); }); }; $scope.deleteFromCart = function(productId){ for(var i=0; i<$scope.customer.cart.length; i++){ var item = $scope.customer.cart[i]; if (item.product[0]._id == productId){ $scope.customer.cart.splice(i,1); break; } } $http.post('/customers/update/cart', { updatedCart: $scope.customer.cart }) .success(function(data, status, headers, config) { $scope.content = '/static/cart.html'; }) .error(function(data, status, headers, config) { $window.alert(data); }); }; $scope.checkout = function(){ $http.post('/customers/update/cart', { updatedCart: $scope.customer.cart }) .success(function(data, status, headers, config) { $scope.content = '/static/shipping.html'; }) .error(function(data, status, headers, config) { $window.alert(data); }); }; $scope.setShipping = function(){ $http.post('/customers/update/shipping', { updatedShipping :$scope.customer.shipping[0] }) .success(function(data, status, headers, config) { $scope.content = '/static/billing.html'; }) .error(function(data, status, headers, config) { $window.alert(data); }); }; $scope.verifyBilling = function(ccv){ $scope.ccv = ccv; $http.post('/customers/update/billing', { updatedBilling: $scope.customer.billing[0], ccv: ccv}) .success(function(data, status, headers, config) { $scope.content = '/static/review.html'; }) .error(function(data, status, headers, config) { $window.alert(data); }); }; $scope.makePurchase = function(){ $http.post('/orders/add', { orderBilling: $scope.customer.billing[0], orderShipping: $scope.customer.shipping[0], orderItems: $scope.customer.cart }) .success(function(data, status, headers, config) { $scope.customer.cart = []; $http.get('/orders/get') .success(function(data, status, headers, config) { $scope.orders = data; $scope.content = '/static/orders.html'; }) .error(function(data, status, headers, config) { $scope.orders = []; }); }) .error(function(data, status, headers, config) { $window.alert(data); }); }; }]);
11. 初始化应用程序
本程序已经完成 ,你需要在数据库中创建初始的Customer Order Product
文档,有几种不同的方法可以做到这一点,以下是使用一个基本的NodeJs脚本完成。
首先执行清理,清楚顾客、订单和产品的集合,然后创建一个Customer
文档和一个Order
文档,之后增加了一些Product
文档,并且向Customer
文档的购物车和Order
文档的物品中添加了Product
文档。
//cart_init.jsvar mongoose = require('mongoose');var db = mongoose.connect('mongodb://localhost:27017/cart');require('./models/cart_model.js');var Address = mongoose.model('Address');var Billing = mongoose.model('Billing');var Product = mongoose.model('Product');var ProductQuantity = mongoose.model('ProductQuantity');var Order = mongoose.model('Order');var Customer = mongoose.model('Customer');function addProduct(customer, order, name, imagefile, price, description, instock){ var product = new Product({name:name, imagefile:imagefile, price:price, description:description, instock:instock}); product.save(function(err, results){ order.items.push(new ProductQuantity({quantity: 1, product: [product]})); order.save(); customer.save(); console.log("Product " + name + " Saved."); });}Product.remove().exec(function(){ Order.remove().exec(function(){ Customer.remove().exec(function(){ var shipping = new Address({ name: 'Customer A', address: 'Somewhere', city: 'My Town', state: 'CA', zip: '55555' }); var billing = new Billing({ cardtype: 'Visa', name: 'Customer A', number: '1234567890', expiremonth: 1, expireyear: 2020, address: shipping }); var customer = new Customer({ userid: 'customerA', shipping: shipping, billing: billing, cart: [] }); customer.save(function(err, result){ var order = new Order({ userid: customer.userid, items: [], shipping: customer.shipping, billing: customer.billing }); order.save(function(err, result){ addProduct(customer, order, 'Delicate Arch Print', 'arch.jpg', 12.34, 'View of the breathtaking Delicate Arch in Utah', Math.floor((Math.random()*10)+1)); addProduct(customer, order, 'Volcano Print', 'volcano.jpg', 45.45, 'View of a tropical lake backset by a volcano', Math.floor((Math.random()*10)+1)); addProduct(customer, order, 'Tikal Structure Print', 'pyramid.jpg', 38.52, 'Look at the amazing architecture of early America.', Math.floor((Math.random()*10)+1)); addProduct(customer, order, 'Glacial Lake Print', 'lake.jpg', 77.45, 'Vivid color, crystal clear water from glacial runoff.', Math.floor((Math.random()*10)+1)); }); }); }); });});
11. 项目完成
至此,本购物车项目已经完成,具备基本的购物车功能。
源代码已经上传,点击这里
或者直接从github拉取,点击跳转到远程仓库
- NodeJS+Angular+Mongodb Web开发(2)
- NodeJs+Angular+Mongodb Web开发(1)
- NodeJs+Angular+Mongodb Web开发(3)
- NodeJS+Angular+Mongodb Web开发(4)
- angular+nodejs+mongodb架构
- Node.js MongoDB Angular Web开发 ( 1 )
- nodejs+angular+mongodb实现论坛基本功能
- mean(mongodb+express+angularjs+nodejs) web开发在线参考资料
- NodeJS+MongoDB+nginx 开发
- 搭配nodejs mongodb开发环境
- NodeJs的web开发
- nodejs mongodb (2)
- 采用基于NodeJS的express+Mongodb技术快速开发web应用
- 使用nodejs+mongodb+百度开放云开发微信或web应用
- Angular JS 开发Web应用程序
- Angular 2 CRUD application using Nodejs
- 全方位的NodeJS+mongodb开发环境搭建
- NodeJS+Express3.2.2+MongoDB开发教程
- 1.begin
- maven POM.xml 标签详解
- 网页中配置使用MathJax
- Operator Overloading
- python IDLE的执行py文件
- NodeJS+Angular+Mongodb Web开发(2)
- selenium配置firefox profile, 创建firefox profile
- 基于.NET的开源GIS项目收集整理
- 【tool】logminer的使用
- gnuradio安装指南——详解ubuntu16.04下使用脚本安装gnuradio&uhd全过程
- 棉花1分钟时间周期的套利模型(有问题)
- Instability(Ramsey定理+快速幂)
- PHP 代码更新延迟 PHP代码没及时更新解决方案
- 堆和栈的特点