《Pro AngularJS》学习小结-02

时间:2014-05-05 23:38:30   收藏:0   阅读:559

上一篇的项目只有一个单独的模板页面,加入了相应的controller,filter,使得页面上的数据能够动态的变化。现在我们开始建立并整合多个模板,加入购物车模块和结账checkout模块。

一、在页面中处理Ajax的错误

在storesSport.js中我们已经有了在申请Ajax请求错误时候的处理代码,其实在页面中也可以加入Ajax请求错误的信息,这样更容易调试,更加符合用户经验(user experience)设计原则。

bubuko.com,布布扣

修改index.html

bubuko.com,布布扣
<body ng-controller="sportsStoreCtrl">
  <div class="navbar navbar-inverse">
    <a class="navbar-brand" href="#">SPORTS STORE</a>
  </div>
  <div class="alert alert-danger" ng-show="data.error">
    Error ({{data.error.status}}). The product data was not loaded.
    <a href="/index.html" class="alert-link">Click here to try again</a>
  </div>
  <div class="panel panel-default row" ng-controller="productListCtrl" ng-hide="data.error">
  <div class="col-xs-3 col-md-3">
  .....
</body>
bubuko.com,布布扣

二、建立多模板 —— partial views

有两种方法使用多个模板

1. 分离模板—— 先使用ng-include方法

建立partial/productList.html文件

bubuko.com,布布扣
<div class="panel panel-default row" ng-controller="productListCtrl" ng-hide="data.error">
  <div class="col-xs-3 col-md-3">
    <a ng-click="selectCategory()" class="btn btn-block btn-default btn-lg">Home</a>
    <a ng-repeat="item in data.products | orderBy:‘category‘ | unique:‘category‘"
      ng-click="selectCategory(item)" class=" btn btn-block btn-default btn-lg"
      ng-class="getCategoryClass(item)">
      {{item}}
    </a>
  </div>
  <div class="col-xs-8 col-md-8">
    <div class="well" ng-repeat="item in data.products | filter:categoryFilterFn | range:selectedPage:pageSize">
      <h3>
        <strong>{{item.name}}</strong>
        <span class="pull-right label label-primary">
          {{item.price | currency}}
        </span>
      </h3>
      <span class="lead">{{item.description}}</span>
    </div>
    <div class="pull-right btn-group">
      <a ng-repeat="page in data.products | filter:categoryFilterFn | pageCount:pageSize"
         ng-click="selectPage($index + 1)" class="btn btn-default"
         ng-class="getPageClass($index + 1)">
        {{$index + 1}}
      </a>
    </div>
  </div>
</div>
bubuko.com,布布扣

在index.html文件中删除相应内容,更改为

bubuko.com,布布扣
......
<
body ng-controller="sportsStoreCtrl">   <div class="navbar navbar-inverse">     <a class="navbar-brand" href="#">SPORTS STORE</a>   </div>   <div class="alert alert-danger" ng-show="data.error">     Error ({{data.error.status}}). The product data was not loaded.     <a href="/app.html" class="alert-link">Click here to try again</a>   </div>   <ng-include src="‘partial/productList.html‘"></ng-include> </body>
......
bubuko.com,布布扣

2. 加入购物车

The basic flow of the shopping cart

bubuko.com,布布扣

定义购物车module和service —— cart.js

bubuko.com,布布扣

bubuko.com,布布扣
angular.module("cart", [])
    .factory("cart", function () {
        var cartData = [];
        return {
            addProduct: function (id, name, price) {
                var addedToExistingItem = false;
                for (var i = 0; i < cartData.length; i++) {
                    if (cartData[i].id == id) {
                        cartData[i].count++;
                        addedToExistingItem = true;
                        break;
                    }
                }
                if (!addedToExistingItem) {
                    cartData.push({
                        count: 1, id: id, price: price, name: name
                    });
                }
            },
            removeProduct: function (id) {
                for (var i = 0; i < cartData.length; i++) {
                    if (cartData[i].id == id) {
                        cartData.splice(i, 1);
                        break;
                    }
                }
            },
            getProducts: function () {
                return cartData;
            }
        }
});
bubuko.com,布布扣

这里在新的cart模块中创建了一个自定义的service——cart。每个AngularJS的service都是一个简单的Javascript的单例对象,可以在整个程序application中访问之。

所以把购物车cart设置为service,因为在整个程序中每个组件component都可以访问cart,看到cart中的信息。 

有多种方法建立service,什么情况下该建立什么样的service,这个以后慢慢研究,^_^。

3. 创建购物车directive ——一个Cart Widget

bubuko.com,布布扣

3.1 创建directive

bubuko.com,布布扣
angular.module("cart", [])
    .factory("cart", function () {
        var cartData = [];
        return {
            ......
        }
    })
    .directive("cartSummary", function (cart) {
        return {
            restrict: "E",
            templateUrl: "/partial/cartSummary.html",
            controller: function ($scope) {
                var cartData = cart.getProducts();
                $scope.total = function () {
                    var total = 0;
                    for (var i = 0; i < cartData.length; i++) {
                        total += (cartData[i].price * cartData[i].count);
                    }
                    return total;
                };
                $scope.itemCount = function () {
                    var total = 0;
                    for (var i = 0; i < cartData.length; i++) {
                        total += cartData[i].count;
                    }
                    return total;
                };
            }
        };
});
bubuko.com,布布扣

bubuko.com,布布扣

在这个cartSummary

 

3.2 创建cartSummary.html模板——partial view

bubuko.com,布布扣
<style>
    .navbar-right { float: right !important; margin-right: 5px;}
    .navbar-text { margin-right: 10px; }
</style>
<div class="navbar-right">
    <div class="navbar-text">
        <b>Your cart:</b>
        {{itemCount()}} item(s),
        {{total() | currency}}
    </div>
    <a href="#" class="btn btn-default navbar-btn">Checkout</a>
</div>
bubuko.com,布布扣

3.3 应用到index.html

bubuko.com,布布扣
<!DOCTYPE html>
<html ng-app="sportsStore">
<head>
    <title>First Test</title>
    ......
    <script>
        angular.module("sportsStore", ["customFilters", "cart"]);
    </script>
    <script src="js/controllers/sportsStore.js"></script>
    <script src="js/controllers/productListControllers.js"></script>
    <script src="js/filters/customFilters.js"></script>
    <scriptsrc="js/factory/cart.js"></script>
</head>
<body ng-controller="sportsStoreCtrl">
<div class="navbar navbar-inverse">
    <a class="navbar-brand" href="#">SPORTS STORE</a>
    <cart-summary />
</div>
<div class="alert alert-danger" ng-show="data.error">
    Error ({{data.error.status}}). The product data was not loaded.
    <a href="index.html" class="alert-link">Click here to try again</a>
</div>
<ng-include src="‘productList.html‘"></ng-include>
</body>
</html>
bubuko.com,布布扣

4. 增加“添加到购物车”按钮

bubuko.com,布布扣

4.1 修改productListControllers.js

bubuko.com,布布扣
angular.module("sportsStore")
    .constant("productListActiveClass","btn-primary")   //highlight the selected category
    .constant("productListPageCount",3)     //define pagination
    .controller("productListCtrl", function ($scope, $filter, productListActiveClass,
               productListPageCount,cart) {
        ......
        $scope.addProductToCart = function(product){
            cart.addProduct(product.id,product.name,product.price);
        }
});
bubuko.com,布布扣

4.2 修改productList.html

bubuko.com,布布扣
<div class="panel panel-default row" ng-controller="productListCtrl" ng-hide="data.error">
    ......
    <div class="col-xs-8 col-md-8">
        <div class="well" ng-repeat="item in data.products | filter: categoryFilter | range:selectedPage:pageSize">
            <h3>
                ......
            </h3>
            <button ng-click="addProductToCart(item)" class="btn btn-success pull-right">Add to cart</button>
            <span class="lead">{{item.description}}</span>
        </div>
        ......
    </div>
</div>
bubuko.com,布布扣

5. 定义URL路由导航——URL Navigation

5.1  新建partial/checkoutSummary.html

bubuko.com,布布扣
<div class="lead">
    This is the checkout summary view
</div>
<a href="#/products" class="btn btn-primary">Back</a>
bubuko.com,布布扣

说明: 这里的href="#/products"中的#不能省略,我一开始没有使用#,结果打死也找不到页面。以后其他模板中的链接都是一样。

5.2 定义URL routes

接下来我们希望点击checkout按钮跳转到checkoutSummary.html页面中,在checkoutSummary.html页面中点击“Back”跳转到产品信息页面中,这是ng-include就不够用了。

bubuko.com,布布扣
<!DOCTYPE html>
<html ng-app="sportsStore">
<head>
......
    <script>
        angular.module("sportsStore", ["customFilters", "cart", "ngRoute"])
                .config(function ($routeProvider) {
                    $routeProvider.when("/complete", {
                        templateUrl: "/partial/thankYou.html"
                    })
                    .when("/placeorder", {
                        templateUrl: "/partial/placeOrder.html"
                    })
                    .when("/checkout", {
                        templateUrl: "/partial/checkoutSummary.html"
                    })
                    .when("/products", {
                        templateUrl: "/partial/productList.html"
                    })
                    .otherwise({
                        templateUrl: "/partial/productList.html"
                    });
                });
    </script>
    <script src="js/controllers/sportsStore.js"></script>
    <script src="js/controllers/productListControllers.js"></script>
    <script src="js/filters/customFilters.js"></script>
    <script src="js/factory/cart.js"></script>
    <script src="js/lib/angular-route.js"></script>
</head>
<body ng-controller="sportsStoreCtrl">
......
<ng-view/>   <!-- 也可以写成 <div ng-view></div> -->
</body>
</html>
bubuko.com,布布扣

5.3 修改cartSummary.html

bubuko.com,布布扣
<div class="navbar-right">
    ......
    <a href="#/checkout" class="btn btn-default navbar-btn">Checkout</a>
</div>
bubuko.com,布布扣

现在可以实现结账跳转功能了。

bubuko.com,布布扣

6. 完善结账功能

6.1 新建一个checkoutControllers.js

bubuko.com,布布扣
angular.module("sportsStore")
.controller("cartSummaryController", function ($scope, cart) {
    $scope.cartData = cart.getProducts();
    $scope.total = function () {
        var total = 0;
        for (var i = 0; i < $scope.cartData.length; i++) {
            total += ($scope.cartData[i].price * $scope.cartData[i].count);
        }
        return total;
    }
    $scope.remove = function (id) {
        cart.removeProduct(id);
    }
});
bubuko.com,布布扣

该js中包含一个controller——cartSummaryController,依赖于cart service,通过定义一个scope属性——cartData来获得cart的数据,并定义了一个total行为计算购物车的总价,一个remove行为来从购物车中移除产品。

6.2 完善checkoutSummary.html

bubuko.com,布布扣
<h2>Your cart</h2>
<div ng-controller="cartSummaryController">
    <div class="alert alert-warning" ng-show="cartData.length == 0">
        There are no products in your shopping cart.
        <a href="#/products" class="alert-link">Click here to return to the catalogue</a>
    </div>
    <div ng-hide="cartData.length == 0">
        <table class="table">
            <thead>
            <tr>
                <th>Quantity</th>
                <th>Item</th>
                <th class="text-right">Price</th>
                <th class="text-right">Subtotal</th>
            </tr>
            </thead>
            <tbody>
            <tr ng-repeat="item in cartData">
                <td class="text-center">{{item.count}}</td>
                <td class="text-left">{{item.name}}</td>
                <td class="text-right">{{item.price | currency}}</td>
                <td class="text-right">{{ (item.price * item.count) | currency}}</td>
                <td><button ng-click="remove(item.id)" class="btn btn-sm btn-warning">Remove</button></td>
            </tr>
            </tbody>
            <tfoot>
            <tr>
                <td colspan="3" class="text-right">Total:</td>
                <td class="text-right">{{total() | currency}}</td>
            </tr>
            </tfoot>
        </table>
        <div class="text-center">
            <a class="btn btn-primary" href="#/products">Continue shopping</a>
            <a class="btn btn-primary" href="#/placeorder">Place order now</a>
        </div>
    </div>
</div>
bubuko.com,布布扣

bubuko.com,布布扣

三、订单管理功能——如何使用Angular Form和Form validation

1. 新建placeOrder.html

bubuko.com,布布扣

bubuko.com,布布扣
<!-- 在这里可自定义AngularJS表单验证的样式ng-valid和ng-invalid -->
<
style> .ng-invalid { background-color: lightpink; } .ng-valid { background-color: lightgreen; } span.error { color: red; font-weight: bold; } </style> <h2>Check out now</h2> <p>Please enter your details, and we‘ll ship your goods right away!</p> <form name="shippingForm" novalidate> <!-- 表示该表单必须通过验证 --> <div class="well"> <h3>Ship to</h3> <div class="form-group"> <label>Name</label> <input name="name" class="form-control" ng-model="data.shipping.name" required /> <span class="error" ng-show="shippingForm.name.$error.required"> Please enter a name </span> </div> <h3>Address</h3> <div class="form-group"> <label>Street Address</label> <input name="street" class="form-control" ng-model="data.shipping.street" required /> <span class="error" ng-show="shippingForm.street.$error.required"> Please enter a street name </span> </div> </form>
bubuko.com,布布扣

 2. “complete order”按钮的验证——如果不填写完表单,该按钮无效

bubuko.com,布布扣

bubuko.com,布布扣
...
<div class="text-center">
    <button ng-disabled="shippingForm.$invalid" class="btn btn-primary">Complete order</button>
</div>
...
bubuko.com,布布扣
bubuko.com,布布扣
bubuko.com,布布扣
<style>
    .ng-invalid { background-color: lightpink; }
    .ng-valid { background-color: lightgreen; }
    span.error { color: red; font-weight: bold; }
</style>
<h2>Check out now</h2>
<p>Please enter your details, and we‘ll ship your goods right away!</p>
<form name="shippingForm" novalidate>
    <div class="well">
        <h3>Ship to</h3>
        <div class="form-group">
            <label>Name</label>
            <input name="name" class="form-control" ng-model="data.shipping.name" required />
            <span class="error" ng-show="shippingForm.name.$error.required">
                Please enter a name
            </span>
        </div>
        <h3>Address</h3>
        <div class="form-group">
            <label>Street Address</label>
            <input name="street" class="form-control" ng-model="data.shipping.street" required />
            <span class="error" ng-show="shippingForm.street.$error.required">
                Please enter a street name
            </span>
        </div>
        <div cla="form-group">
            <label>City</label>
            <input name="city" class="form-control"
                   ng-model="data.shipping.city" required />
            <span class="error" ng-show="shippingForm.city.$error.required">
            Please enter a city
            </span>
        </div>
        <div class="form-group">
            <label>State</label>
            <input name="state" class="form-control"
                   ng-model="data.shipping.state" required />
            <span class="error" ng-show="shippingForm.state.$error.required">
            Please enter a state
            </span>
        </div>
        <div class="form-group">
            <label>Zip</label>
            <input name="zip" class="form-control"
                   ng-model="data.shipping.zip" required />
            <span class="error" ng-show="shippingForm.zip.$error.required">
            Please enter a zip code
            </span>
        </div>
        <div class="form-group">
            <label>Country</label>
            <input name="country" class="form-control"
                   ng-model="data.shipping.country" required />
            <span class="error" ng-show="shippingForm.country.$error.required">
            Please enter a country
            </span>
        </div>
        <h3>Options</h3>
        <div class="checkbox">
            <label>
                <input name="giftwrap" type="checkbox"
                       ng-model="data.shipping.giftwrap" />
                Gift wrap these items
            </label>
        </div>
        <div class="text-center">
            <button ng-disabled="shippingForm.$invalid" class="btn btn-primary">Complete order</button>
        </div>
    </div>
</form>
placeOrder.html的完整代码
bubuko.com,布布扣

3. 表单发送功能

3.1 修改sportsStore.js——加入controller(behavior)

bubuko.com,布布扣
angular.module("sportsStore")
    //.contant("dataUrl","http://localhost:8081/products")
    .constant("orderUrl", "http://localhost:8081/orders")
    .controller("sportsStoreCtrl", function ($scope, $http, $location, orderUrl, cart) {
        $scope.data = {};
        $http.get("products.json")
            .success(function(data){
                $scope.data.products = data;
            }).error(function(error){
                $scope.data.error = error;
            });
        $scope.sendOrder = function(shippingDetails){
            var order = angular.copy(shippingDetails);
            order.products = cart.getProducts();
            $http.post(orderUrl, order)
                .success(function(data){
                    $scope.data.orderId = data.id;
                    cart.getProducts().length = 0;
                })
                .error(function(error){
                    $scope.data.orderError = error;
                }).finally(function(){
                        $location.path("/complete")
                    });
        };
});
bubuko.com,布布扣

3.2 在placeOrder.html加入ng-click事件

bubuko.com,布布扣
<div class="text-center">
       <button ng-disabled="shippingForm.$invalid" ng-click="sendOrder(data.shipping)" class="btn btn-primary">
                Complete order
       </button>
</div>
bubuko.com,布布扣

3.3 新建thankYou.html

bubuko.com,布布扣
<div class="alert alert-danger" ng-show="data.orderError">
    Error ({{data.orderError.status}}). The order could not be placed.
    <a href="#/placeorder" class="alert-link">Click here to try again</a>
</div>
<div class="well" ng-hide="data.orderError">
    <h2>Thanks!</h2>
    Thanks for placing your order. We‘ll ship your goods as soon as possible.
    If you need to contact us, use reference {{data.orderId}}.
</div>
bubuko.com,布布扣

说明: 这里要用到数据库,我没有实现,还在研究NodeJS和数据库中,估计等过一阵子再发布Angular的文章了

《Pro AngularJS》学习小结-02,布布扣,bubuko.com

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!