足以给应用绑定了硬编码数据集中的三条手机数据,让咱们从咱们的服务中适配更大的数据集,他使用Angular内建的 服务中 $htttp。咱们将使用Angular的 依赖注入给 PhoneListCtrl
提供服务。 如今有20条手机,从服务器中读取。 工做空间重置介绍 重置你的工做区间到第五步 html
git checkout -f step-5
刷新你的浏览器,或者在线上检出这一步:第五步例子。 大部分重要的修改都列在下面,你在 GitHub上能看所有不一样。git
app/phones/phones.json
文件在你的项目中是一个数据集,他包含一个用JONS格式存储的手机大列表。 下面是简单的文件angularjs
[ { "age": 13, "id": "motorola-defy-with-motoblur", "name": "Motorola DEFY\u2122 with MOTOBLUR\u2122", "snippet": "Are you ready for everything life throws your way?" ... }, ... ]
咱们使用Angular的 $http服务,在咱们控制器中制做HTTP请求来从 app/phones/phones.json
文件中读取数据。$http是一系列 Angular内建的服务,他在web应用中处理相同的操做,Angular在你须要的地方注入这些服务。 服务由Angular的 DI子系统管理,依赖注入帮助你构建应用能既有良好的结构(像描述,数据,控制控件操做)和松耦合(组件之间的依赖不是组件本身,而是由依赖注入了系统解决。) app/js/controllers.js:github
var phonecatApp = angular.module('phonecatApp', []); phonecatApp.controller('PhoneListCtrl', function ($scope, $http) { $http.get('phones/phones.json').success(function(data) { $scope.phones = data; }); $scope.orderProp = 'age'; });
$http制造一个HTTP GET 请求去咱们Web服务器,请求 phones/phones.json
(这个url放在咱们的index.html页面中),服务器响应json文件中的数据(这个响应多是后端服务器动态生成,浏览器和咱们的应用看到的是同样,在教程为了简单的目的咱们使用json文件) $http服务返用成功方法返回一个 Promise对象,对于phones模型,咱们调用这个方法去处理异步响应,经过控制器将手机数据赋给scope。注意Angular检测json响应,解析给咱们。 为了使用Angular中的服务,你简单定义了依赖的名字,作为控制器的构造器的参数,如:web
phonecatApp.controller('PhoneListCtrl', function ($scope, $http) {...}
当控制器被构建时,Angular的依赖注入器提供服务给你的控制器,依赖注入器也当心地建立服务可能有的过渡依赖(服务可能依赖其余服务)。 注意参数的名字很重要,由于注册器用他们寻找依赖。json
你能够建立本身的服务,实际上咱们刚好在作第11步的事,作为命名规定,Angular的内建服务,范围方法和其余一些Angular 应用接口在名字前有$前缀。 $前缀在这里是Angular提供服务的名字空间,为了防止冲突,最好是避免你的服务和模型其余东西用 $
开关。 若是你检查一个范围,你可能注意有些属性是用 $$
开关,这些属性是被认为是私有,不能被读取或修改。后端
当Angular从控制器构建方法的参数名字中推导控制器的依赖,若是你 压缩 PhoneListCtrl
的JavaScript代码,全部的方法参数都会压缩良好,依赖注入器可能不能正确识别服务。 咱们能用依赖的名字的注解来避免这个问题,注解提供的字符串不会被最小化,这里有两种方法提供注入注解。api
在控制器中,建立一个持有一个字符数组的$inject属性,数组中的每一个字符串是对应于要注入服务的参数的名字,在咱们的例子中能够这么写:数组
function PhoneListCtrl($scope, $http) {...} PhoneListCtrl.$inject = ['$scope', '$http']; phonecatApp.controller('PhoneListCtrl', PhoneListCtrl);
使用一行注解,代替咱们刚刚提供的方法,你提供一个数组,数组包括服务名称的列表,后面跟着函数:promise
function PhoneListCtrl($scope, $http) {...} phonecatApp.controller('PhoneListCtrl', ['$scope', '$http', PhoneListCtrl]);
两种方法均可以经过Angular给任何函数注入,因此选择那个决定于你的工程风格。 当咱们使用第二种方法,经常使用方法是当注入控制器时在一行内提供匿名函数构建器。
phonecatApp.controller('PhoneListCtrl', ['$scope', '$http', function($scope, $http) {...}]);
从这点出发,咱们将在教程中使用行内方法,用这种意图,让咱们增长一个注解给咱们的 PhoneListCtrl
app/js/controllers.js:
var phonecatApp = angular.module('phonecatApp', []); phonecatApp.controller('PhoneListCtrl', ['$scope', '$http', function ($scope, $http) { $http.get('phones/phones.json').success(function(data) { $scope.phones = data; }); $scope.orderProp = 'age'; }]);
test/unit/controllersSpec.js: 由于咱们开始使用依赖注入,而且咱们的控制器有了依赖,构造控制器在咱们测试中有一点复杂,咱们使用new操做符,提供有某些假$http实现的控制器,可是 Angular提供模拟$http服务,咱们能用他来作单元测试,咱们配置“假”响应服务经过调用服务上的方法,服务响应。
describe('PhoneCat controllers', function() { describe('PhoneListCtrl', function(){ var scope, ctrl, $httpBackend; // Load our app module definition before each test. beforeEach(module('phonecatApp')); // The injector ignores leading and trailing underscores here (i.e. _$httpBackend_). // This allows us to inject a service but then attach it to a variable // with the same name as the service in order to avoid a name conflict. beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) { $httpBackend = _$httpBackend_; $httpBackend.expectGET('phones/phones.json'). respond([{name: 'Nexus S'}, {name: 'Motorola DROID'}]); scope = $rootScope.$new(); ctrl = $controller('PhoneListCtrl', {$scope: scope}); }));
注意:由于在咱们的测试环境中读取Jasmin和angular-mocks.js,咱们用两个帮助方法 module和 inject来读取各配置注入器。 咱们在测试环境中建立控制器,以下:
咱们使用inject帮助方法去注入$rootScope,$controller和$httpBackend服务实例给Jasmine的beforeEach函数,这些实例来自注入器,每一个单个测试都会被从新建立,这样确实每一个测试开始于好的开始点,每一个测试工做时与其余测试都隔离开。
咱们建立一个中$rootScope.$new()
的新范围给咱们的控制器。
咱们调用注入的$controller
函数,经过名叫PhoneListCtrl
的控制器,并建立一个scope作为参数。
由于咱们在控制器中使用了 $http
服务读取数据,在咱们建立PhoneListCtrl子scope以前,咱们告诉测试从控制器中驾驭一个指望的请求,咱们这样作:
请求$httpBackend服务注入到beforeEach
函数,模拟版本的服务在生产环境能使XHR和JSONP请求更容易,模拟版本的服务容许你在没有本地API和全局状态关联状况下写测试,他们两个都让测试成为噩梦。
使用$httpBackend.expectGET
方法让$httpBackend
服务期待Http请求到来,并告诉他怎么返回,注意响应直到调用$httpBackend.flush方法后才会返回。
如今让咱们建立一个断言验证phones模型在响应接到以前不存在于scope中。
it('should create "phones" model with 2 phones fetched from xhr', function() { expect(scope.phones).toBeUndefined(); $httpBackend.flush(); expect(scope.phones).toEqual([{name: 'Nexus S'}, {name: 'Motorola DROID'}]); });
在浏览器中,咱们经过调用$httpBackend.flush()
刷入请求队列,这样经过$http
服务用准备好的response产生promise的返回值。在mock $httpBackend
文档中看‘刷入Http请求’,解释为何这是必须的。
咱们建立断言,验证手机模型如今存在有scope中。
最后,咱们验证orderProp默认值设定正确。
it('should set the default value of orderProp model', function() { expect(scope.orderProp).toBe('age'); });
如今你能够在Karma选项卡中查看下面的输出。
Chrome 22.0: Executed 2 of 2 SUCCESS (0.028 secs / 0.007 secs)
在index.html底部,增长 <pre>{{phones | filter:query | orderBy:orderProp | json}}</pre>
绑定去看json格式的手机列表。 在PhoneListCtrl控制器中,经过限制列表第一次手机的数目到5来预处理HTTP响应。在回调时,使用下面的代码。
$scope.phones = data.splice(0, 5);
如今你已经学了使用Angular服务是多么容易(谢谢Angular的依赖注入),到 第6步,你将给手机增长一些缩略图和连接。 原文地址: https://docs.angularjs.org/tutorial/step_05