6.1:SportStore:一个忠实的采取

故此想写这篇作品,是自个儿久久来说平素想把Modeler和SPSS应用在脚下的玩家数量解析和采购充值分析方面,游戏数量解析针对的部落到实处在和电信,网络,电子商务很像,属于虚拟经济的分层,并且要通过数据化的手段,结合集团自己的BI建设及小卖部数目解析人士的钻研解决一些坚苦的难点。KNN作为一种分类算法的应用领域很宽,很广,即便并未归咎树,后向传播等那么百步穿杨,可是依然要学习的和动用的。

事先的小例子让我们演示了AngularJS的一部分特点,但她们紧缺上下文。要缓解那几个难点,小编要开创一个简单单真实的电子商务应用。

KNN可以行使在对新方案的评估和预测方面,当然要组成已有的样本(陶冶多少)举办对测试数据的分类和预测,那样就可见成功诸如电信新增套餐的创立,FPS同种类武器的立异把握和行销推断等等。

小编将开创一个在线产品分类,客户可以透过分类和页面浏览,一个购物车用户增加或移除产品,当客户在结账时,进入他们的购物明细,列出她们的订单。作者也会创制一个管理区域,蕴含CRUD,管理分类,并且珍重它,唯有已经报到的管理员才能修改它。

KNN(k-Nearest Neighbor algorithm )分类算法是最简便易行的机器学习算法之一,拔取向量空间模型来分类,概念为同样类其余案例,彼此的相似度高,而得以借由总结与已知连串案例之相似度,来评估未知体系案例可能的归类。

KNN依据某些样本实例与其它实例之间的相似性举办分拣。特征相似的实例相互靠近,特征不一般的实例相互远离。因此,可以将七个实例间的距离作为她们的“不一般度”的一种度量标准。KNN模型可以支撑三种方式统计实例间距离,他们分别是:Euclidean
Distance( 欧氏距离法 ) 和 City-block Distance(四会市距离法)。

百度宏观:

若是一个样书在特色空间中的k个最相似(即特征空间中最接近)的范本中的半数以上属于某一个系列,则该样本也属于那么些项目。KNN算法中,所挑选的街坊都是一度不错分类的目标。该措施在定类决策上只根据最贴近的一个或者几个样本的连串来支配待分样本所属的体系。
KNN方法就算从规律上也凭借于极端定理,但在档次决策时,只与极少量的邻座样本有关。由于KNN方法紧要靠周围有限的贴近的样书,而不是靠判别类域的法子来规定所属连串的,由此对此类域的陆续或重叠较多的待分样本集来说,KNN方法较其余艺术尤其适合。

 

  KNN算法不仅可以用于分类,仍是可以用来回归。通过找出一个样本的k个近年来邻居,将这几个邻居的属性的平均值赋给该样本,就可以取得该样本的性质。更管用的法门是将分歧距离的左邻右舍对该样本发生的熏陶给予分歧的权值(weight),如权值与离开成正比。

维基百科:

方法

  • 对象:分类未知连串案例。
  • 输入:待分类未知种类案例项目。已知序列案例集合D
    ,其中包含 j个已知类其余案例。
  • 输出:项目可能的档次。

步骤

小编本章的对象,通过创造一个更真实的例子,是让你倍感到,一个实打实的AngularJS开发。小编想关怀于AngularJS,当然,也要简单地与表面系统融为一体,如数据存储,会全盘忽视任何的,如开发处理。

 

  1. 依公式总结 Item 与 D1、D2 … …、Dj
    之相似度。得到Sim(Item, D1)、Sim(Item, D2)… …、Sim(Item,
    Dj)。
  2. 将Sim(Item, D1)、Sim(Item, D2)…
    …、Sim(Item,
    Dj)排序,如若超越一般度门槛t则放入邻居案例集合NN。
  3. 自邻居案例集合NN中取出前k名,依多数决,得到Item可能系列。

但是k近来邻居法因为总计量格外的大,所以一定的耗时,Ko与Seo提议一算法TCFP(text
categorization using feature projection),尝试运用特色投影法(en:feature
projection)来下跌与分类毫无干系的表征对于系统的震慑,并借此升高系统效用,其实实验结果突显其分类效果与k目前邻居法相近,但其运算所需时日仅需k近日邻居法运算时间的五至极之一。

除去针对文件分类的频率,尚有探讨针对性怎么着促进k如今邻居法在文书分类方面的功效,如Han等人于2002年尝试运用贪心法,针对文件分类实做可调动权重的k目前邻居法WAkNN
(weighted adjusted k nearest
neighbor),以牵动分类功用;而Li等人于二零零四年提议由于不相同分类的文件本身有数据上有差距,由此也应有根据操练集合中各个分类的公文数量,拔取不一样数额的近年邻居,来参与分类。

案例演示:

某汽车创设厂商的研发部门制定出五款新预研车型的技能设计目标。厂商的决策机构希望将其和早已投放到市场上的已有车型的有关数据举办相比较,从而分析新车型的技术指标是还是不是合乎预期,并展望新车型投放到市场将来,预期的销售额是稍微。(来自IBM
DeveloperWorks)

值得指出的是KNN算法在IBM
SPSS Statistics和Modeler中均有使用,今日将运用IBM SPSS
Modeler进行出现说法KNN算法应用。

KNN是基于观测值与其他观测值的接近程度分类观测值的法子。在机械学习中,将其付出为识别数据方式的一种方法,而不必要与其他存储情势或观测值完全匹配。相似个案互相接近,非一般个案则相互远离。因而,四个观测值之间的相距是其不相似性的测量。

将走近相互的个案视为“相邻元素。”当提议新的观测值(保留观测值)时,统计其到模型中各种观测值的相距。计算最相似观测值–近期相邻元素–的归类并将新观测值放在包蕴最多新近附近元素的体系中。

大家可以规定须求查验的近期紧邻元素(近期邻居)的数据;此值叫做k。图片展现怎么运用四个不等的k值分类新观测值。当k=5时,新观测值将被放置种类1中,因为半数以上如今邻近元素属于类型
1。但当 k = 9 时,新观测值将被置于系列 0
中,因为半数以上以来紧邻元素属于类型 0。

“如今邻居数量 K
在如今邻元素分析模块建模中起到了很大的功能。K
的取值分裂,将会造成对新实例分类结果的不等。如图
1所示,每个实例按照其目的变量取值(0 和
1)的分化,被分入多个品类集合。当 K=5
时,与新实例连接的旧实例(邻居)当中,目的变量取值为 1
的实例数更加多,所以新实例被分到连串 1 当中。然则,当 K=9
时,目标变量取值为 0 的邻里更加多,由此新实例被分到种类 0 当中。Statistics
的近年邻元素分析模型既允许用户指定固定的 K
值,也支撑根据实际数据自动为用户挑选 K 值。

KNN模型支撑 feature
selection(预测变量采用)的效力,允许在用户输入的居多的估算变量当中,只接纳部分预测变量用作建模,使得建立的模子效果更好。

KNN模型允许建立目的变量是延续型变量的模子,在那种处境下,目的变量的平均值或者中位数值将用作新的实例目的的预测值。

一般来说图为转移 k
对分类的熏陶

电子商务 1

互动接近的实例被誉为“Neighbors(邻居)”。当大家向模型中引入一条新的实例,它和模型当中早已存在的每一个实例之间的离开将会被总结出来。那样,与这条新实例最相近的街坊就被区分出来了。图中讲述了一个目的变量是离散型变量的方今邻模型,
紫色五角星是新实例,白色和灰色的点是模型当中已有实例。与他近年来的近邻们都被用红线连接了四起。

数据处理格局

参考IBM
DeveloperWorks的 SPSS Statistics办法

增产多少的技术目的(变量音信)

电子商务 2

创建商收集了有关水土保持车型的不等类其余数目,并添加了其原型产品的详细新闻。要求在不一致车型间开展相比较的品类包涵以千为单位的价钱
(price)、发动机尺寸(engine_s)、马力 (horsepow)、轴距(wheelbas)、车宽
(width)、车长 (length)、整车重量 (curb_wgt)、油箱容量(fuel_cap)
和燃油作用 (mpg)。

在原数据文件当中扩大两条新的笔录:

电子商务 3

追加热点变量

接下来,大家要为那两条新记录加上尤其关爱的标志,那亟需为具有记录扩展新的变量。通过菜单
Transform->Compute Variable(转换 ->
总结变量),打开总计变量对话框,如图所示。

电子商务 4

键入 focal 作为 Target
variable(目的变量),在 Numeric
Expression(数字表明式)文本框当中键入表达式:

any(model,
‘newCar ‘,’newTruck’)。按照这么些表明式,对于随意一条记下,其 model
变量的取值假诺是 newCar 或 newTruck,则它的 focal 变量的取值被安装为
1,否则被装置为 0。

电子商务 5

充实分区变量

再扩大一个新变量
partition,以分别 Training( 陶冶数据子集 ) 和 Holdout( 测试 )
子集,大家将已有车型视为磨练多少子集,而新车型为测试子集。如图所示。

电子商务 6

只顾在数字表明式文本框中填入
1-any(model, ‘newCar’,’newTruck’),使得变量 partition 的取值与变量 focal
正好相反。之所以那样做是由于算法中规定:partition > 0
表示为教练多少,那三个新车型作为测试数据,将其 partition 设为 0;而
focal = 1 为重大关怀对象。

使用Modeler14进行模型解析

第一在Modeler14中导入SPSS文件,执行打开连接,数据方式如下:

电子商务 7

花色节点设置

将“类型”节点连接到原数据节点上,右键编辑,打开窗口如下:

电子商务 8

参数设置

只在字段 price 至 mpg
上开展比较,由此保持所有那个字段的角色设置为输入。将具有其他字段
(manufact 至 type)
的角色设置为无。将最后一个字段分区的测量级别设置为标志。确保将其角色设置为输入。单击读取值以读取数据值到流中,单击确定。

上述为KNN模型数据解析的多寡准备阶段,此后就算具体的模子数据处理和分析阶段,时间和字数所限该阶段将在后来继续形成。

参考:

[1]IBM
DeveloperWorks(http://www.ibm.com/developerworks/cn/data/library/techarticle/dm-1201gex/

[2]IBM SPSS
Modeler14.0手册

[3]百度完善:KNN

[4]维基百科:KNN

唤醒:单元测试

AngularJS对单元测试提供不可计数超人的支撑,但作者不可能在本书的最终一章才说它。因为您确实须求领悟AngularJS如何行事,才能写出综合的单元测试。

作者在第25章才讲单元测试,可是他提出咱们按梯次读,那样才能明了单元测试的风味,是什么创设的。

  1. 开始

那里要设置一些可选的AngularJS特性,来安装服务器,让她分发数据。

  1. 未雨绸缪数据

首先步是开创一个新的Deployd应用。你要成立一个途径,来放生成的文本。小编称它路径叫deployd,放在angularjs文件夹同级别。

在意:作者在率先章让你下载Deployd,如若您没那么做,快去下载吧。

在命令行中,进入新路径,输入下边代码

dpd create sportsstore

要起来新服务器,输入上边的授命

dpd –p 5500 sportsstore\app.dpd

dashboard 

提醒:这是windows风格的公文分隔符。你在其余平台上或许是sportsstore/app.dpd。

在Deployd dashboard,用于配打败务器,突显在浏览器中。

  1. 始建数据结构

下一步是全速Deployd,要存储的数码的社团。在dashboard上点击黑色的大按钮,从pop-up菜单中,选用Collection。设置集合的名字为
“/products”(没有双引号)。

Deployd会提示您穿件JSON对象的特性,属性如下:

Name

Type

Required

name

String

Yes

description

String

Yes

category

String

Yes

price

Number

Yes

当您做到了质量添加,dashboard会匹配,确保您输入的习性名字不错,并选拔了正确的项目。

提示:注意Deployd已经添加id属性。他会用于独一无二地标识数据库中的对象。Deployd会自动指派独一无二的值给id属性。在第8章,当小编完毕管理员功能时,会依据这么些值。

  1. 加上数据

现在,小编曾经定义了目的的布局。小编可以添加产品的周详。点击Data
link,在右侧。他会显得grid编辑器,让您填入属性的值。

绝不操心指派id属性的值,因为Deployd会自动生成他们。

提示:Deployd的number字段的浮点显示。

  1. 测试数据服务

要测试Deployd已经不易配置并工作,打开浏览器窗体,导航到上边的URL:

http://localhost:5500/products

若果你已经在地方电脑安装Deployd,并不曾更改它的端口号。/products
URL是查询/products集合中的内容,作为一个JSON字符串标示。注意,id字段分歧。

  1. 未雨绸缪使用

在小编初始写应用前,小编需求准备angularjs文件夹,来创制路径结构,放置AngularJS和Bootstrap文件。

1.2.1、创立路径结构

在angularjs文件夹下,成立如下目录:

Name

Description

components

包含自包含的客制化AngularJS组件

controllers

包含应用的控制器,作者会在第13章讲。

filters

包含自定义filters。作者在第14章深度介绍filters

ngmodules

包含可选的AngularJS模块。

views

包含SportsStore应用的局部视图。Views包含指令和filters的组合。作者在第10-17章讲。

 

1.2.2、安装AngularJS和BootStrap文件

小编的习惯,将AngularJS JavaScript文件和Bootstrap
CSS文件平素放到angularjs路径,将AngularJS可选模块放在ngmodules路径。

Angularjs文件夹下有:angular.js,bootstrap.css,bootstrap-theme.css

Ngmodules文件夹下有:angular-route.js,angular-resource.js

 

1.2.3、营造基本的文稿

作者喜欢先用静态数据模拟各种部分的情节,发轫一个新的AngularJS应用。SportsStroe应用的骨干布局,是经典的两列布局。第一列是分类,用户过滤第二列要来得的产品组。

率先步是要创制一个世界级HTML文件。在angularjs文件夹下,新建app.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", []);

</script>

</head>

<body>

<div class="navbar navbar-inverse">

<a class="navbar-brand" href="#">SPORTS STORE</a>

</div>

<div class="panel panel-default row">

<div class="col-xs-3">

Categories go here

</div>

<div class="col-xs-8">

Products go here

</div>

</div>

</body>

</html>

该文件包蕴多少个AngularJS指定,第三个是调用angular.module方法。

<script>

angular.module("sportsStore", []);

</script> 

模块是AngularJS应用的顶尖创设块,该方法调用穿件一个新的模块,叫做sportsStroe。

其次个地点,是html元素上的ng-app指令:

<html ng-app="sportsStore"> 

Ng-app指令使得sportsStore模块中定义的成效,在HTML范围内可用。小编喜欢将ng-app指令应用到html元素上,你也足以放在body元素上。

提示:用http://localhost:5000/app.html
。来走访该页面。而不是Deployd服务器的5500端口。

  1. 来得模拟产品数量

小编先定义本地模拟初阶化数据,第7章会用从Deployd服务器取得的数目替换该多少。

2.1、创设控制器

第一要加一个控制器。该控制器创设后,会为整个应用服务,作者成为头等控制器。然后,小编会将多少个有关的控制器,放到一个文件中,但把顶尖控制器放在app.html文件中。

提醒:小编保持超级控制器和任何文件分割的来由,是它在版本控制系统发出变更时,要一眼就能观察它。当主功效逐步形成,一流控制器会爆发逐渐暴发变化,那是潜在地打破,大概在颇具的使用中。那一点在开发周期中,小编想要知道顶尖控制器前边的有的事物,可以确保改变经过了丰硕的测试。

在controllers/sportsStore.js :

angular.module("sportsStore")

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

$scope.data = {

products: [

{ name: "Product #1", description: "A product",

category: "Category #1", price: 100 },

{ name: "Product #2", description: "A product",

category: "Category #1", price: 110 },

{ name: "Product #3", description: "A product",

category: "Category #2", price: 210 },

{ name: "Product #4", description: "A product",

category: "Category #3", price: 202 }]

};

});

注意第一行调用angular.module方法,那在app.html也有雷同的不二法门调用。差异之处是,在app.html中定义的module,小编提供了一个外加的参数,像这么:

angular.module("sportsStore", []);

第四个参数是一个数组,它现在是空的,它是sportsStore模块基于的模块列表,它高速AngularJS,定位并提供这么些模块中包蕴的职能。小编稍后会添法郎素到那一个数组中。可是现在,主要的是,要明了,当您提供一个数组——空或不空,它都高速AngularJS,要创造一个新的模块。当你品尝创立一个模块,不过它已经存在时,AngularJS会报告一个破绽百出,所以您必要保险您的模块名字的唯一性。

用作比较,在sportsStroe.js文件中调用angular.module方法,不带有首个参数:

angular.module("sportsStore")

忽视第三个参数,会报告AngularJS,你要固定一个曾经定义过的模块,在那种情况下,倘若指定的模块不设有,AngularJS会报告一个荒谬,
所以你要力保模块已经被成立。

利用angular.module方法重返的Module对象,都能被用来定义应用功用。小编曾经接纳controller方法,定义了一个控制器。

专注:小编不常像这么在HTML文件中,成立主应用模块,因为他得以被简单地停放到Javascript文件中。小编将宣示分成若干小部分的案由,是几度施用angular.module方法,导致无终止的眼花缭乱,小编想让你注意到它。

SportsStore应用中,顶尖控制器的最紧要角色,是概念用于在不一致视图上体现的多寡。在第13章,相会到七个控制器级联排列。

小心:当作者定义控制器的范围上的数码时,将数据对象的数组,定义在data上,它会附加到scope。你必须在定义数据时那么些小心,因为一旦你在scope上一直指派属性(如$scope.products=[data]),因其余控制器可以读取,但延续不可能改改数据。作者将在第13章详细表达。

2.2、突显产品明细

要突显产品明细,须要给app.html文件添加一些HTML。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", []);

</script>

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

</head>

<body ng-controller="sportsStoreCtrl">

<div class="navbar navbar-inverse">

<a class="navbar-brand" href="#">SPORTS STORE</a>

</div>

<div class="panel panel-default row">

<div class="col-xs-3">

Categories go here

</div>

<div class="col-xs-8">

<div class="well" ng-repeat="item in data.products">

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

</div>

</body>

</html>

那边有四个转变。首个,添加了一个script元素,导入sportsStore.js文件。该文件包括sportsStoreCtrl控制器。因为小编曾经在app.html文件中定义了sportsStore模块,然后在sportsStore.js文件中一定并行使它,小编需求有限支撑sportsStore模块的定义script,现身在引用以前。

首个转移,是用ng-controller指令,将控制器采纳到视图,像那样:

<body ng-controller="sportsStoreCtrl">

小编会使用sportsStoreCtrl控制器,为全方位应用提供支撑,所以,他把它利用到body元素上。

2.2.1、生成内容元素

末尾一个变更,是成立了出品明细元素。AngularJS提供的一个最实用的指令,是ng-repeat,它为数量数组中的每个对象生成元素。

<div class="well" ng-repeat="item in data.products">

然后小编在数码绑定表明式中,引用当前目标。

<div class="well" ng-repeat="item in data.products">

<h3>

<strong>{{item.name}}</strong>

<span class="pull-right label label-primary">{{item.price | currency}}</span>

</h3>

<span class="lead">{{item.description}}</span>

</div>

Name和description值被直接插入HTML元素,但price属性不是那般:小编采纳了一个filter。一个filter格式或order,是要在view中显得的数据值。AngularJS有一些内建的filters,包括currency
filter,它用币种金额,格式化数字。Filters使用 | 符号应用。Item.price |
currency,会告知 AngularJS,使用currency
filter,传递item对象的price属性的值。

Currency
filter默认使用USD格式,但小编会在第14章表明,怎么采用AngularJS本地化filters,来浮现任何币种格式。小编也会在第14章,表明内建filters,并给您来得怎么创立和谐的。

  1. 来得分类列表

下一步是显得分类列表,让用户可以过滤突显的产品组。完成该特性,须要变更客户用于导航的因素,选用一个出品分类后,更新明细面板,只显示被选中分类的制品。

电子商务,3.1、创制分类列表

小编想从成品数据对象动态变化分类元素,而不是硬编码HTML元素。动态途径设置起来更扑朔迷离一点,但它会容许SportsStore应用能活动感应产品分类的成形。那代表作者不得不从产品数量对象中变化一个无比的归类名称的列表。该特性AngularJS不含有,但透过成立和动用一个自定义过滤器,可以简单地促成。在filters路径下,创建一个customFilters.js:

angular.module("customFilters", [])

.filter("unique", function () {

return function (data, propertyName) {

if (angular.isArray(data) && angular.isString(propertyName)) {

var results = [];

var keys = {};

for (var i = 0; i < data.length; i++) {

var val = data[i][propertyName];

if (angular.isUndefined(keys[val])) {

keys[val] = true;

results.push(val);

}

}

return results;

} else {

return data;

}

}

});

自定义过滤器,使用Module对象的filter方法定义,它通过angular.module方法得到并创办。小编选拔新建一个模块,叫做customFilters,来含有他的过滤器,主要可以显得怎么样定义并在应用中组成多少个模块。

提醒:当您给现存模块添加组件或创办一个新模块时,没有先后顺序。作者希望她定义的作用在今后的不比拔取里重用时,他赞成于成立模块。自定义过滤器倾向于可选拔,因为数量格式是任何AngularJS应用都急需的,也是开发者需要的公物格式。

Filter方法的参数,是filter的名字,例子中是unique,它回到一个factory
function,该函数并不实际工作,而是重临一个filter
function。当AngularJS必要创建一个filter的实例时,它调用factory
function,filter function就会被调用,以举行过滤。

享有的filter
function都有一个参数,传递他们需求的格式的数目,但小编的filter定义了一个外加的参数,叫做propertyName,它能用于指定要从要生成哪个字段的绝无仅有列表。过滤效果的落到实处很粗略:枚举数据对象的内容,用propertyName参数,营造一个旷世的值的列表。

唤醒:作者没有没有将过滤器功用硬编码为寻找category属性,那会限制unique过滤器在别的使用的任用。

过滤效果重临过滤后的多少。小编运用anagular.isArray和angular.isString,检查传入的多寡是或不是是数组,属性名是或不是是字符串。然后,他用angular.isUndefined方法,检查该属性是或不是定义。AngularJS提供一组有用的工具方法,包蕴允许你检核查象和总体性类型。小编会在第5章完整地叙述。假若过滤器接收到一个数组和一个属性名,然后她转移并回到一个无比的属性值的数组。不然,他回去将收取到的数据稳如五台山地回到。

升迁:让过滤器仅突显用户须要的内容,而不是在scope中修改原始数据。

3.2、生成分类导航链接

下一步,生成用户可以点击的出品分类的领航链接。那须要动用上节创造的unique过滤器。

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

</head>

<body ng-controller="sportsStoreCtrl">

<div class="navbar navbar-inverse">

<a class="navbar-brand" href="#">SPORTS STORE</a>

</div>

<div class="panel panel-default row">

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

{{item}}

</a>

</div>

<div class="col-xs-8">

<div class="well" ng-repeat="item in data.products">

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

</div>

</body>

</html>

在sportsStore模块中,定义一个对customFilters的看重性。

angular.module("sportsStore", ["customFilters"]);

那就是declaring a
dependency。在本例中,小编讲明sportsStore模块着重于customFilters模块的法力。那会促成AngularJS定位customFilters模块,并有限协助它可用,然后可以引用它含有的机件,如过滤器和控制器。该进度叫做resolving
the dependency。

提示:注解和管理模块和其他品种组件的经过,叫做dependency
injection,是AngularJS的基本,小编会在第9章解释该进程。

3.2.1、生成导航元素

最有趣的的片段,是行使ng-repeat元素,为每个产品分类生成一个因素。

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

{{item}}

</a>

Ng-repeat属性值的率先局地,和转变产品明细的同样,item in
data.products,它告诉ng-repeat指令要枚举data.products数组的对象,指派当前目的给叫做item的变量,并复制利用该指令的a元素。

属性值的第二部分,告诉AngularJS,传递data.products数组给叫做orderBy的内建过滤器,用于排序数组。该orderBy过滤器,有一个参数,指定用于排序的属性。作者会在第14章完整地叙述orderBy过滤器。

唤醒:注意小编在单引号之间,指定了属性名。默许地,AngularJS假使表达式中的名字,指向scope中定义的变量。要指定一个静态值,不得不拔取字符串,在Javascript中,须要单引号或双引号。

过滤器有一个很棒的表征,通过 |
将他们链式调用。AngularJS依据过滤器排列的次第,应用他们。那代表,category属性在排序过后,才传递给unique过滤器。你看看小编怎么着指定unique过滤器要操作的性质:

<a ng-repeat="item in data.products | orderBy:’category’ | unique:’category’"

这么的结果是,data.products数组传递给orderBy过滤器,它依照category属性排序。Ta排序过的数组传递给unique,它回到一个字符串数组,包括独一无二的category值———因为unique过滤处理进程中不更改值的相继,结果保持上个过滤器的排序。

提示:小编能够颠倒使用过滤器的顺序,结果同样。分裂的是,orderBy过滤器会功用于一个字符串数组,而不是product对象。orderBy过滤器设计用来操作对象的,但您可以经过行使orderBy:’toString()’,来排序字符串。不要忘了引号,不然,AngularJS找一个名为toString的scope属性,而不是调用toString方法。

3.2.2、处理点击事件

作者在a元素上应用ng-click指令,可以对应用户的点击。AngularJS提供一组内建命令,作者将在第11章介绍,它们恩可以在对应事件时,简单地调用控制器行为。ng-click指令的名字,指出指明AngularJS在点击事件触发时,要做什么样。

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

{{item}}

</a>

在app.html中有八个a元素。第二个是静态地,创造Home按钮,小编用户显示所有成品的持有分类。在该因素中,作者设置ng-click指令,它调用一个控制器行为,叫做selectCategory,没有参数。后边作者会创建该作为,现在,紧要的业务是无时或忘另一个a元素,它的selectCategory行为有一个item变量值作为参数。点击时,例如selectCategory(‘Category
#1’)。

3.3、选拔分类    

在浏览器中点击分类按钮,不会有其他功用,因为ng-click指令设置为调用一个还未曾定义的所作所为。当你品味访问一个不设有的一坐一起或数额时,AngularJS不会埋怨。那给debugging带来了小麻烦,因为浮现错误结果,但也更灵活。作者将在第13章描述怎么样在更深的地点拔取控制器和它的界定。

3.3.1、定义控制器

作者要定义叫做selectCategory的作为,来响应用户对分类按钮的点击。他不像将作为添加到五星级sportsStoreCtrl控制器上,那是整套应用提供行为和多少的地点。取而代之,小编新建一个控制器,专用于产品列表和分类视图。controllers/productListControllers.js。

升迁:你恐怕会问我,为何自己的控制器的名字,比过滤器的更标准。原因是,过滤器更通用,准备在其它使用中录取。

angular.module("sportsStore")

.controller("productListCtrl", function ($scope, $filter) {

var selectedCategory = null;

$scope.selectCategory = function (newCategory) {

selectedCategory = newCategory;

}

$scope.categoryFilterFn = function (product) {

return selectedCategory == null ||

product.category == selectedCategory;

}

});

小编调用app.html文件中定义的sportsStroe模块的controller方法(记住,一个参数的angular.module方法,以为那找现有模块,而四个参数的趣味,是创制一个新模块)。

该控制器叫做productListCtrl,它定义一个称作selectCategory的表现。该控制器还定义了一个号称categoryFilterFn的一言一动,它以一个出品对象作为参数,它在并未分类被选中,或有一个分类被入选并且该产品输入它时,重返true。

唤醒:注意selectedCategory变量没有概念在scope上,它只是一个例行的JavaScript变量,意味着它不可能从指令访问或view的数目绑定中。那样做的结果是,创造了selectCategory行为,用于安装分类,categoryFilterFn用于过滤产品对象,但被选中的归类的细节,保持私有。小编在SportStore应用中,不借助于此特性。

3.3.2、应用控制器和过滤产品

小编不得不采用ng-contorller指令,应用控制器到视图,让ng-click指令可以调用selectCategory行为。不然,包括ng-click指令的因素的归来,会是一级sportsStoreCtrl控制器,它不包蕴该表现。

<!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="panel panel-default row" ng-controller="productListCtrl">

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

{{item}}

</a>

</div>

<div class="col-xs-8">

<div class="well"

ng-repeat="item in data.products | filter:categoryFilterFn">

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

</div>

</body>

</html>

小编添加script元素,导入productListControllers.js文件,在包蕴分类列表和产品列表的视图部分,使用ng-controller指令来行使productListCtrl控制器。

将productListCtrl控制器放在sportsStorectrl控制器范围内,意味着小编可以运用先进的controller
scope
inheritance,小编将在第13章解释。productListCtrl继承sportsStoreCtrl中定义的data.products数组和其余其余数据和行事。那样做的好处,是足以界定控制器功用在使用上的限定,更易于执行单元测试,放置组件间非预期的借助。

另一个改观,是在转变产品明细的ng-repeat上配置:

<div class="well" ng-repeat="item in data.products | filter:categoryFilterFn">

AngularJS提供的一个内建的过滤器,叫做filter。它处理一个会见,选用她带有的目的的子集。小编将在第14章描述该技术。通过在ng-repeat指令上应用它,确保只有当前被入选的分类的制品浮现。

3.4、高亮被选中的分类

用户可以点击分类按钮,来过滤产品,但尚无视觉反馈,哪个范磊被选中了。小编将为当选的分类应用btn-primary
CSS
class。第一步,在控制器中添加一个作为,它接受一个分类。如若它是被选中的归类,重回CSS
class名。

提醒:注意小编怎么在AngularJS模块上链式调用方法。那是因为Module定义的章程,同样再次回到Module,这一点和fluent
API一样。

angular.module("sportsStore")

.constant("productListActiveClass", "btn-primary")

.controller("productListCtrl", function ($scope, $filter, productListActiveClass) {

var selectedCategory = null;

$scope.selectCategory = function (newCategory) {

selectedCategory = newCategory;

}

$scope.categoryFilterFn = function (product) {

return selectedCategory == null ||

product.category == selectedCategory;

}

$scope.getCategoryClass = function (category) {

return selectedCategory == category ? productListActiveClass : "";

}

});

小编不想在作为代码里指定class的名字,所以小编拔取在Moduled对象上使用constant方法,定义一个称作productListActiveClass的固定值。它同意我改变class,每一遍要采取时。要在控制器中访问该值,小编不得不注解constant名字作为依靠,如下边那样。

.controller("productListCtrl", function ($scope, $filter, productListActiveClass) {

随即,可以在getCategoryClass行为中,使用productListActiveClass,它大约地检讨它接受到的分类,重回class
名字或空字符串。

getCategoryClass行为看起来有点出其不意,但它能够在每个分类导航按钮中调用,传递分类的名字作为参数。要动用CSS
class,作者选拔ng-class指令。

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

Ng-class属性,它会选用geCategoryClass再次回到的class 名。小编将在第11章讲。

3.5、添加分页

分页,几次展现一定数量的成品。须求三步才能达成分页:修改控制器,scope跟踪分页状态,已毕过滤器,更新视图。

3.5.1、更新控制器

在productListControllers.js文件中,更新控制器,以跟踪分页。

angular.module("sportsStore")

.constant("productListActiveClass", "btn-primary")

.constant("productListPageCount", 3)

.controller("productListCtrl", function ($scope, $filter,

productListActiveClass, productListPageCount) {

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 : "";

}

});

每页产品的数额被定义为常量,叫做productListPageCount。在控制器里,小编在scope上定义变量,曝露常量值(所以作者能在view上访问它)和如今被选用的页。小编曾经定义了表现,selectPage,允许被增选的页,编程其余页。getPageClass,设计用来ng-class指令,来高亮被入选的页,和事先被入选的归类一样。

提拔:你恐怕会纳闷,为啥视图不可以平昔访问常量值,而是要通过scope来适合地露出。答案是,AngularJS努力放置组件间紧密地耦合,小编在第3章描述过。要是视图可以一向访问服务和常量值,那么她不难截止无终止的耦合和看重,难于测试和维护。

3.5.2、已毕过滤

在customFilters.js文件中开创四个新的过滤器。

angular.module("customFilters", [])

.filter("unique", function () {

return function (data, propertyName) {

if (angular.isArray(data) && angular.isString(propertyName)) {

var results = [];

var keys = {};

for (var i = 0; i < data.length; i++) {

var val = data[i][propertyName];

ChAPTeR6 ■SPORTSSTORe: A ReAl APPlICATIOn

144

if (angular.isUndefined(keys[val])) {

keys[val] = true;

results.push(val);

}

}

return results;

} else {

return data;

}

}

})

.filter("range", function ($filter) {

return function (data, page, size) {

if (angular.isArray(data) && angular.isNumber(page) && angular.isNumber(size)) {

var start_index = (page 1) * size;

if (data.length < start_index) {

return [];

} else {

return $filter("limitTo")(data.splice(start_index), size);

}

} else {

return data;

}

}

})

.filter("pageCount", function () {

return function (data, size) {

if (angular.isArray(data)) {

var result = [];

for (var i = 0; i < Math.ceil(data.length / size) ; i++) {

result.push(i);

}

return result;

} else {

return data;

}

}

});

率先个新的过滤器,叫做range,从一个数组中回到一队列元素,代表出品页。过滤器接收参数,当前被入选的页(用于申明range的始发index),和page
size(用于声明end index)。

Range过滤器不是特意有趣,不相同于我已经在职能上提供的一个内建过滤器,叫做limitTo,它从一个数组中,重回指定编号的项。要利用该过滤器,我再$filter服务上定义了一个凭借。它让作者成立并采用filter的实例。作者将在地14章解释详细,最要紧的是那句讲明:

return $filter("limitTo")(data.splice(start_index), size);

小编运用的JavaScript
标准措施splice的结果是选项数据数组的一局地,然后将它传递给limitTo过滤器,来选用要在该页突显的。limitTo过滤器确保遍历数组不是难点,如若指定的数字不可用,会回到多少个items。

第三个过滤器,pageCount,是一个污秽的——但有利的——hack。Ng-repeat指令使得生成内容很简短,但它根据数据数组工作。你无法,例如,让她再度指定的次数。小编的过滤器计算出页码的一个数组。

小心:小编让过滤器的功用绕开受限制的ng-repeat指令,那是那些危急的,不过个应急方法。更好的代表格局,会在第16,17章看到,让ng-repeat指令生成指定次数的要素。

3.5.3、更新视图

更新app.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"]);

</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="panel panel-default row" ng-controller="productListCtrl">

<div class="col-xs-3">

<a ng-click="selectCategory()"

class="btn btn-block btn-default btn-lg">Home</a>

ChAPTeR6 ■SPORTSSTORe: A ReAl APPlICATIOn

146

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

首先处变更,是ng-repeat指令,生成产品列表,数据会通过range过滤器,过滤选拔当前页的出品。当前页的细心,和每页产品的数目,使用小编定义在控制器scope上值作为参数,传递给过滤器。

第二处改动,是添加了导航按钮。小编选取ng-repeat指令,统计出脚下选中的归类,有多少页产品,传递结果给pageCount过滤器,那会导致ng-repeat指令生成不易数量的导航页按钮。当前当选的页,通过ng-class指令表达,通过ng-click指令,页面变化。

 

 

 

 

 

 

 

 

 

Leave a Comment.