Now that the routing configuration is in place, I am going to turn to the checkout process. My first task is to define a new controller called cartSummaryController, which I have placed in a new file called controllers/ checkoutControllers.js. Listing 7-14 shows the contents of the new file.
Listing 7-14. The Contents of the checkoutControllers.js File
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);
}
});
The new controller is added to the sportsStore module and depends on the cart service. It exposes the contents of the cart through a scope property called cartData and defines behaviors to calculate the total value of the products in the cart and to remove a product from the cart. Using the features created by the controller, I can replace the temporary content in the checkoutSummary.html file with a summary of the cart. Listing 7-15 shows the changes I have made.
Listing 7-15. Revising the Contents of the checkoutSummary.html File
<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>
There are no new techniques in this view. The controller is specified using the ng-controller directive, and I use the ng-show and ng-hide directives to show a warning when there are no items in the cart and a summary when there are. The ng-repeat directive is used to generate rows in a table for each product in the cart, and the details are displayed using data bindings. Each row contains unit and total pricing and a button that uses the ng-click directive to invoke the remove controller behavior and remove an item from the cart.
The two a elements at the end of the view allow the user to navigate elsewhere in the application:
…
<a class=”btn btn-primary” href=”#/products“>Continue shopping</a>
<a class=”btn btn-primary” href=”#/placeorder“>Place order now</a>
…
The Continue shopping button returns the user to the product list by navigating to the #/products path, and the Place order button navigates to a new URL path, #/placeorder, which I will configure in the next section.
1. Applying the Checkout Summary
The next step is to add a script element to the app.html file and define the additional routes that I will need to complete the checkout process, as shown in Listing 7-16.
Listing 7-16. Applying the Checkout Summary to the app.html File
<!DOCTYPE html>
<html ng-app=”sportsStore”>
<head>
<title>SportsStore</title>
<script src=”angular.js”></script>
<link href=”bootstrap.css” rel=”stylesheet” />
<link href=”bootstrap-theme.css” rel=”stylesheet” />
<script>
angular.module(“sportsStore”, [“customFilters”, “cart”, “ngRoute”])
.config(function ($routeProvider) {
$routeProvider.when(“/complete”, {
templateUrl: “/views/thankYou.html”
});
$routeProvider.when(“/placeorder”, {
templateUrl: “/views/placeOrder.html”
});
$routeProvider.when(“/checkout”, {
templateUrl: “/views/checkoutSummary.html”
});
$routeProvider.when(“/products”, {
templateUrl: “/views/productList.html”
});
$routeProvider.otherwise({
templateUrl: “/views/productList.html”
});
});
</script>
<script src=”controllers/sportsStore.js”></script>
<script src=”filters/customFilters.js”></script>
<script src=”controllers/productListControllers.js”></script>
<script src=”components/cart/cart.js”></script>
<script src=”ngmodules/angular-route.js”></script>
<script src=”controllers/checkoutControllers.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=”/app.html” class=”alert-link”>Click here to try again</a>
</div>
<ng-view />
</body>
</html>
The new routes associate URLs with views that I will create in the next chapter. Figure 7-7 shows the cart summary that is now presented when the user clicks the Checkout button on the cart widget.
Source: Freeman Adam (2014), Pro AngularJS (Expert’s Voice in Web Development), Apress; 1st ed. edition.