NodeJS+Angular+Mongodb Web开发(2)

来源:互联网 发布:c语言带小数点数字求和 编辑:程序博客网 时间:2024/06/04 18:44

1. 项目简介

  本项目提供了实现一个购物车的实际例子,允许你添加、删除物品,经历结账过程,查看订单等,这个例子可以让你了解在结账过程中,如何利用AngularJS在视图之间进行切换。

  本项目创建的购物车提供了所需的大部分功能,但是省略了诸如身份验证和错误处理等细节,只是单纯地设计到与购物车有关的东西,其余一概省略。

 例如本例子采用一个userid(用户ID)被硬编码为customerA的用户,所以不太可能直接用于生产,除非你在此基础上花费不小的功夫继续扩展。


2. 基本流程

本实例的一般逻辑流程如下:

这里写图片描述


3. 用到的库

  1. express:作为项目的主web服务器
  2. body-parser:为post请求提供JSON正文支持
  3. ejs:用于呈现HTML模板
  4. mongodb:用于访问MongoDB数据库
  5. mongoose:用于提供结构化的数据模型
  6. 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>&nbsp;|&nbsp;</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控制器代码来支持它们。

可以分解成以下步骤:

  1. 初始化购物车作用域
    $scope.months$scope.years 数组填充信用卡表单,$scope.content 决定了在视图中呈现哪个AngularJS部件,它被初始化为products.html,这样用户就可以开始购物。

  2. 实现辅助函数
    setContent() 函数设置设置$scope.content值,用以改变视图
    cartTotal() 函数遍历用户购物车中的产品,更新$scope.shipping,并返回一个随后在购物车和复核视图中使用的金额。

  3. 将物品添加到购物车
    当用户点击Add To Cart按钮时,调用addToCart()函数,此函数首先遍历customer.cart中的物品,如果发现已经存在,则增加此物品数量,否则将该物品添加到customer.cart数组
    一旦$scope.customer被更新,将对/customer/update/cart路由发出一个$http POST请求,来更新购物车,通过这种方式,持久化购物车,即使用户关闭浏览器或者离开购物页面也将存在,如果成功该视图切换到cart.html页面,否则出现一个警告窗口。

  4. 从购物车删除商品
    当用户单击删除Remove按钮时,调用deleteFromCart() 函数,遍历在customer.cart中的物品,如果找到则采用array.slice(index,1)方法数组中删除该物品。
    一旦物品被从$scope.customer.cart删除,对/customer/update/cart路由执行一个$http POST请求,来更新购物车,通过这种方式,持久化购物车,即使用户关闭浏览器或者离开购物页面也将存在,如果成功该视图切换到cart.html页面,否则出现一个警告窗口。

  5. 结账
    当用户在购物车视图单击Checkout按钮时,调用checkout() 函数,发送带有{updatedCart:$scope.customer.cart} 参数的$http POST请求来更新购物车。

  6. 设置发货信息
    当用户在购物车视图单击Continue to Billing按钮时,调用setShipping() 函数,对/customer/update/shipping路由执行一个$http POST请求,在post方法中包括参数{updatedShipping:$scopr.customer.shiiping[0]},如果请求成功,切换到billing.html视图,否则出现警告窗口。

  7. 验证账单
    当用户在发货视图单击Verify Billing按钮时,调用verifyBilling() 函数,信用卡信息可以在这一刻在服务器上进行验证,对/customer/update/billing路由执行一个$http POST请求,如果请求成功,切换到review.html视图,否则出现警告窗口。

  8. 执行购买
    当用户在账单视图单击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拉取,点击跳转到远程仓库

0 0
原创粉丝点击