7.1SportsStore:Navigation and Checkout

  1. 未雨绸缪示例项目
  2. 拔取真实的制品数据

现在,要切换来应用真实的多少,从Deployd服务器获取。

AngularJS通过一个称呼$http的劳动,为Ajax请求提供支撑。小编将在第三片段详尽讲解它是怎么工作的,在第23章讲解$http服务。现在有个不难的认识,修改顶尖控制器sportsStoreCtrl:

angular.module("sportsStore")

.constant("dataUrl", "http://localhost:5500/products")

.controller("sportsStoreCtrl", function ($scope, $http, dataUrl) {

$scope.data = {};

$http.get(dataUrl)

.success(function (data) {

$scope.data.products = data;

})

.error(function (error) {

$scope.data.error = error;

});

});

半数以上JavaScript方法的调用,包括AngularJS组件里的方法,synchronous,意味着在当前职分完结前,不会履行下个表明。在web应用中,那就无法办事,因为大家想让用户在乞请在后台执行,用户可以一连和使用交互。

小编运用Ajax请求获取要求的数目。Ajax基于Asynchronous JavaScript and
XML,主要的是单词asynchronous。一个Ajax请求是一个正经的HTTP请求以异步的办法发出,换句话说,在后台。AngularJS使用promises请求异步操作,那和你利用像jQeury那样的库很像(小编在第5章介绍,并在第20章解释)。

$http服务概念了分歧的法子,来做不相同体系的Ajax请求。Get方法,是作者那里运用的,使用HTTP
GET方法,请求参数中的URL。小编曾经将URL定义为一个誉为dataUrl的常量,并选用第6章中测试过的Deployd服务器的URL。

$http.get方法,从Ajax请求初始,应用持续运行,直到请求已经终结。当服务器已经相应请求,AngularJS须要一种办法,来唤起用户,那就是promise的由来。该$http.get方法再次来到一个目的,定义success和error方法。小编传递函数给这个点子,AngularJS
promises调用那一个函数中的一个,告诉小编,请求是怎样结果。

设若HTTP请求的方方面面都运作很好,AngularJS会调用小编传递给success方法的函数,会自动转换JSON数据为Javascript对象,将她们作为参数传递给函数。若是Ajax
HTTP请求进程中有别的难题,AngularJS会调用小编传递给error方法的函数。

提拔:JSON基于JavaScript Object
Notation,是一种数据互换格式,广泛地运用于web应用。

在success函数中,AngularJS会自动执行JSON数据的更换。小编只需将从服务器获取的数码,指派给控制器scope的data.products变量。Error函数将对象指派给scope的data.error变量,来表明难题。

2.1理解scope

当使用第四回开行,HTML内容被转移和浮现给用户,固然未曾产品音信可用。

在一个点之后,内容渲染完成,数据从服务器回来,指派给scope中的data.products变量。这时,AngularJS更新所有的绑定和计量信赖于产品数量的一言一行的结果,确保新数据传播到利用的每一处。本质上,AngularJS
scope是 live
数据存储,响应和散播改变。你会看出在本书中来看许多如此的例证。

2.2、处理Ajax错误

处理成功的Ajax请求很粗略,因为只需将数据指派个scope,让AngularJS更新视图中持有的绑定和下令。小编不得不有些困难地处理错误,添加一些新元素到视图,用于出现难题是呈现出来。在下边可以看来

<!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"]);

</script>

<script src="controllers/sportsStore.js"></script>

<script src="filters/customFilters.js"></script>

<script src="controllers/productListControllers.js"></script>

</head>

<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>

<div class="panel panel-default row" ng-controller="productListCtrl"

ng-hide="data.error">

<div class="col-xs-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">

<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>

</body>

</html>

小编给视图添加了一个新的div元素,用于浮现错误给用户。使用ng-show指令,当表达式统计结果为true时,显示。

提醒:小编将在第10章描述ng-show和ng-directives。

传送给error函数的目的,定义了status和message属性。状态属性设为HTTP error
code,message属性重返一个字符串,描述难题。作者将status属性包括在message中显示给用户。

  1. 始建部分视图

App.html文件的HTML变得复杂了,将来添加新特色会很糟糕。

万幸的是,作者可以分别文件,使用ng-include指令,在运行时来导入这一个文件。创造view/productList.html文件:

<div class="panel panel-default row" ng-controller="productListCtrl"

ng-hide="data.error">

<div class="col-xs-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">

<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>

小编将成品和归类列表的概念元素,拷贝到HTML文件。部分视图,是HTML的一部分,意味着不须要html,head,body元素。

<!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"]);

</script>

<script src="controllers/sportsStore.js"></script>

<script src="filters/customFilters.js"></script>

<script src="controllers/productListControllers.js"></script>

</head>

<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="’views/productList.html’"></ng-include>

</body>

</html>

升迁:使用部分视图有多少个便宜。第三个是打破应用,使其进一步好管理。第二,创制的HTML片段,可以用于采用中一再重用。第三,使得为用户显示分歧作用区域更易于。笔者会在Defining
URL Routes 这一节再说。

一声令下的创造器,能够指明它被怎么样使用:作为元素,作为质量,作为class,甚至作为HTML
评论。小编将在第16章解释。当AngularJS蒙受ng-include指令,它做一个Ajax请求,加载src属性指定的文本,在该因素地方,插入内容。突显给用户的始末看起来没有啥样分裂,但曾经容易地打扮了app.html文件,将product列表相关的HTML都分开到一个文本中。

升迁:当使用ng-include指令,在单引号中,指定文件的名字。若是没有如此做,那么指令会查找一个scope属性,来得到文件的名字。

  1. 制造购物车

用户可以见到可用的制品,但尚未购物车,作者不可以销售其余东西。

要贯彻购物车特点,许多有的需求扭转,包含要创制一个自定义的AngularJS组件。

4.1、定义购物内衣模特块和服务

到此甘休,都是经过文件的门类社团文件:过滤器包蕴在过滤器文件夹,视图包括在视图文件夹等等。但连续有一部分功用,是自包涵的,但须求混合AngularJS组件。你可以持续用component类型社团文件,但小编找到了更管用的措施,基于他们集体扮演的效益,来协会文件,放在components文件夹下。购物车效用适用于那种社团项目。小编须要不分时图和几个组装件,来得到想要的机能。从成立components/cart文件夹起来,添加一个新的JavaScript文件叫做cart.js:

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;

}

}

});

小编在叫做cart的新模块上穿件一个自定义服务。AngularJS为劳动提供一些效应,(只有一个目的会被制造,并被有着基于该服务的机件共享)。

并不是只有应用一个劳动,才能为大家演示AngularJS的要害特点,但以那种格局贯彻购物车会很好,因为有一个共享的实例,确保其余组件能访问购物车,用户的出品拔取有雷同的视图。

作者将会在第18章解释,基于你要尝尝的完结,那里有例外的点子创制伏务。那里运用Module.factory方法,传入服务的名字(本例中是cart),和一个factory函数。当AngularJS必要劳务时,该factory函数会被调用,成立服务对象,用以相应。因为一个服务目的用于所有应用,factory函数只被调用五遍。

小编的cart服务factory函数,再次来到一个指标,它有多个措施,操作一个尚无通过服务一直暴露的数量数组,那是笔者用于演示的,你不用暴光服务的拥有工作。该cart对象定义多个法子,介绍如下。小编在购物车元帅产品表现为对象,定义了id,name,price属性,来叙述产品,和一个count属性,记录用户添参与篮子的多寡。

Method

Description

addProduct(id,name,price)

添加指定产品到购物车,如果产品已经存在,增加该产品的需求数量

removeProduct(id)

使用指定id,移除产品

getProducts()

返回购物车中的对象数组

 

4.2、创制购物车部件

下一步,要开创一个构件,总计购物车的情节,提必要用户,意味着开首结账流程。上边,作者要开创一个自定义directive。Directives,是子包罗,可选取的效力的单元,它座落AngularJS开发的为主地点。假如您用AngularJS,你会动用过多内建命令。单位了有利于,你会找到您自己创制的自定义命令,来让职能适合你的运用。

利用指令,你能做过多。它竟然支持jQuery的删减版,叫jqLite,来操作DOM元素。一言以蔽之,命令允许你写任何东西,从简单的helpers,到复杂的特色,并控制结果编织成当前的选取,或在其他使用中完全地引用他们。下边是作者给cart.js文件中,创制widget
directive:

angular.module("cart", [])

.factory("cart", function () {

var cartData = [];

return {

// …service statements omitted for brevity…

}

})

.directive("cartSummary", function (cart) {

return {

restrict: "E",

templateUrl: "components/cart/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;

}

}

};

});

因此在AngularJS模块上调用directive方法,创制指令,并传递指令的名字(本例中是cartSummary),和一个factory函数。该函数重返一个directive
definition
object。该指令定义对象定义了质量,会告知AngularJS,你的成色做怎么着,怎么样做。当小编定义cartSumary指令时,定义了五个属性,下边简短地介绍他们。

Name

Description

Restrict

指定指令如何应用。作者使用E的值,意味着该指令只能作为一个元素应用。更公共的值是EA,意味着指令能作为一个元素或一个属性应用。

TemplateUrl

指定哪个URL的部分视图的内容,要插入到指令的元素
controller 制定一个控制器,给部分试图提供数据和行为

简言之,作者的指令定义了一个控制器,告诉AngularJS,使用components/cart/cartSummary.html视图,并限制指令,只能够当作一个要素拔取。

<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 class="btn btn-default navbar-btn">Checkout</a>
</div>

提醒:分布试图包蕴一个style元素,重定义Bootstrap
CSS的导航条的样式。作者不三番五次喜欢将style元素放在视图中,但他那样做了,因为这个样式只影响该准备,并且只是为数不多CSS。在装有其余情况下,小编更期待定义一个单身的CSS文件,导入到应用的主HTML文件中。

该片段视图使用控制器的行事,来显示items的数量,和items的合计值。这里也有一个要素,叫Checkout,点击该按钮,此刻还向来不其余反馈。

4.2.1、应用购物车部件

把购物车部件应用到应用,须要三个步骤:添加script元素,倒入JavaScript文件的始末,添加对cart模块的借助,并丰硕指令元素到markup。

<!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"]);
</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>
</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-include src="'views/productList.html'"></ng-include>
</body>
</html>

在意小编运用cartSummary,定义指令,添加到app.html文件的元素,是cart-summary。AngularJS
normalizes 组建,命名这么些格式之间的照射,小编会在第15章解释。

4.3、添加产品拔取按钮

作为具有AngularJS开发,那里有诸多预支的付出,来开发成效和任何特色,不过那几个事物,如cart,都能在其余应用中引用。小编下一步是给产品明细添加按钮,让用户可以把产品丰盛到购物车。第一,他必要给控制器添加一个行事,让成品列表视图可以操作购物车。下边是controllers/productListController.js文件。

angular.module("sportsStore")
.constant("productListActiveClass", "btn-primary")
.constant("productListPageCount", 3)
.controller("productListCtrl", function ($scope, $filter,
productListActiveClass, productListPageCount, cart) {
var selectedCategory = null;
$scope.selectedPage = 1;
$scope.pageSize = productListPageCount;
$scope.selectCategory = function (newCategory) {
selectedCategory = newCategory;
$scope.selectedPage = 1;
}
$scope.selectPage = function (newPage) {
$scope.selectedPage = newPage;
}
$scope.categoryFilterFn = function (product) {
return selectedCategory == null ||
product.category == selectedCategory;
}

$scope.getCategoryClass = function (category) {
return selectedCategory == category ? productListActiveClass : "";
}
$scope.getPageClass = function (page) {
return $scope.selectedPage == page ? productListActiveClass : "";
}
$scope.addProductToCart = function (product) {
cart.addProduct(product.id, product.name, product.price);
}
});

小编在cart服务上宣称了一个借助,定义了一个名叫addProductToCart的一坐一起,它具备一个成品对象,使用它调用cart服务的addProduct方法。

提醒:在劳务上宣称一个借助,然后通过scope选拔性地展露它的效应,这种格局,在AngularJS开发中很广泛。视图能够通过scope访问可用的表现,然而作者在第六章演示了,当控制器是嵌套的,或者当指令被定义,scopes可以继续另一个scope。

小编然后再产品明细的片段视图上,添加按钮元素,调用addProductToCart行为。

<div class="panel panel-default row" ng-controller="productListCtrl"
ng-hide="data.error">
<div class="col-xs-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">
<div class="well"
ng-repeat=
"item in data.products | filter:categoryFilterFn | range:selectedPage:pageSize">
<h3>
<strong>{{item.name}}</strong>

{{item.price | currency}}

</h3>
<button ng-click="addProductToCart(item)"
class="btn btn-success pull-right">
Add to cart
</button>
{{item.description}}
</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>

唤醒:Bootstrap让小编可以将a和button元素显示成相同的指南,为了方便,他赞同于交替地利用它们。当使用URL
routing时,a元素更有用。

 

5、添加URL导航

路由系统,可以让差异部分准备,自动显示。这使得营造大型应用越来越便于。发轫,小编要求创设一个视图,当用户初叶结账流程时,突显。放在views/checkoutSummary.html文件中。

<div class="lead">
This is the checkout summary view
</div>
<a href="#/products" class="btn btn-primary">Back</a>

 

5.1、定义URL路由

作者要定义一个routes,在制订URL和要出示的视图之间做映射。首先做多个映射,/product和/chekcout
URLs,到产品列表页productList.html和checkoutSummary.html视图。

<!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("/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>
</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>

作者将angular-route.js文件,导入到应用。该文件提供的法力,在一个ngRoute的模块中,小编将它表明为sportsStore模块的看重。

要设置作者的路由,他在模块对象上调用config方法。该办法将一个函数作为他的参数,当模块加载后,单运用还没被实践前,执行该函数。它提供为任何一遍性地安排职务,提供机会。

小编传递给config方法的函数,在一个provider上宣示依赖。作者此前涉嫌,有两样的格局可以成立AngularJS服务,一种就是通过部署provider对象来创立。小编在该provider上宣称的一个看重,是$routeProvider,用于在利用中设置URL路由。

提醒:作者将在第18章,解释什么接纳providers创设服务,在第22章,解释怎么样使用$route服务和$routeProvider。

那那使用$routeProvider对象定义的多个模块,设置他要求的路由。when方法允许小编将URL匹配到视图,象那样:

$routeProvider.when("/checkout", {
templateUrl: "/views/checkoutSummary.html"
});

该注明告诉AngularJS,当URL是/checkout时,他想用/views/checkoutSummary.html文件

突显。同样,也制定了一个具备when方法都不匹配URL时,使用/views/ProductList.html视图文件,来对号入座。这听起来象定义了一个fallback路由。

http://localhost:5000/app.html#/checkout

 

AngularJS不会监视整个URL,因为象http://localhost:5000/checkout
那样的路由,会促成浏览器跳过AngularJS应用,尝试从服务器加载一个不等的文档。

URL Effect
http://localhost:5000/app.html#/checkout  Displays the
checkoutSummary.htmlview
http://localhost:5000/app.html#/products  Displays the
productList.htmlview
http://localhost:5000/app.html#/other Displays the
productList.htmlview (because of the
fallback route defined by the otherwisemethod)
http://localhost:5000/app.html  Displays the productList.htmlview
(because of the
fallback route defined by the otherwisemethod)

提醒:小编在第22章回讲到,你可以利用HTML5 History
API,启用支持,改变URL的监视,使得象http://localhost:5000/checkout
那样的URL也能办事。当心,因为浏览器完毕差距,当用户手工修改URL时,会导致浏览器尝试加载一个分化的文档。

5.1.1、突显路由视图

路由政策,定义了给定URL路径,要显得的视图,但尚未告知AngularJS,将他们加载到哪儿。小编须求运用ng-view指令,它在ngRoute模块中定义。使用ng-view替换ng-include。

<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>

此处不要求安插选项和安装。只需求加上指令,告诉AngularJS,将眼前选拔的视图的内容,插入到什么地方。

5.2、使用URL路由来导航

早已定义了作者的URL路由,并利用ng-view指令,小编可以改变URL路径,来导航应用。首先改变Checkout按钮。

<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="#/checkout" class="btn btn-default navbar-btn">Checkout</a>
</div>

小编给a元素添加了一个href属性,点击该因素,会招致浏览器导航到新URL(它是一定到已经加载过的文档)。该导航变化,会被AngularJS路由劳动意识,导致ng-view指令,呈现checkoutSummary.html视图。

只顾点击checkout后,地址由http://localhost:5000/app.html
变为http://localhost:5000/app.html#/checkout,通过点击重返键,可以回退到上个视图。

运用URL路由的特点是,该组建能够在并未此外准备知识的时候,通过ng-view指令来改变布局。

6、早先结账流程

始建一个誉为cartSummaryController,

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);
}
});

将新控制器添加到sportsStore模块,并依靠于cart服务。它通过一个叫作cartData的scope属性,曝露内容,定义了一个表现,计算购物车中产品的总价值,和从购物车中移除产品。

<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>

此间没有新技巧。该控制器拔取ng-controller指令来制定,当购物车中尚无产品时,或有产品时,用ng-show和ng-hide指令来显示一个告诫。

 

6.1、应用结账计算

下一步是添加一个script元素到app.html文件,并定义附加routes,用于完结结账流程。

<!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>

相关文章