微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

5-XHRs(XmlHttpRequest)与依赖注入

足以给应用绑定了硬编码数据集中的三条手机数据,让我们从我们的服务中适配更大的数据集,他使用Angular内建的 服务$htttp。我们将使用Angular的 依赖注入PhoneListCtrl提供服务。 现在有20条手机,从服务器中读取。 工作空间重置介绍 重置你的工作区间到第五步

gitcheckout-fstep-5

刷新你的浏览器,或者在线上检出这一步:第五步例子 大部分重要的修改都列在下面,你在 GitHub上能看全部不同。

数据

app/phones/phones.json文件在你的项目中是一个数据集,他包含一个用JONS格式存储的手机大列表。 下面是简单的文件

[
{
"age":13,"id":"motorola-defy-with-motoblur","name":"MotorolaDEFY\u2122withMOTOBLUR\u2122","snippet":"Areyoureadyforeverythinglifethrowsyourway?"
...
},...
]

控制器

我们使用Angular的 $http服务,在我们控制器中制作HTTP请求来从 app/phones/phones.json文件中读取数据。$http是一系列 Angular内建的服务,他在web应用中处理相同的操作,Angular在你需要的地方注入这些服务。 服务由Angular的 DI子系统管理,依赖注入帮助你构建应用能既有良好的结构(像描述,数据,控制控件操作)和松耦合(组件之间的依赖不是组件自己,而是由依赖注入了系统解决。) app/js/controllers.js:

varphonecatApp=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中的服务,你简单定义了依赖的名字,做为控制器的构造器的参数,如:

phonecatApp.controller('PhoneListCtrl',$http){...}

当控制器被构建时,Angular的依赖注入器提供服务给你的控制器,依赖注入器也小心地创建服务可能有的过渡依赖(服务可能依赖其他服务)。 注意参数的名字很重要,因为注册器用他们寻找依赖。

$前缀命名规定

你可以创建自己的服务,实际上我们恰好在做第11步的事,做为命名规定,Angular的内建服务,范围方法和其他一些Angular 应用接口在名字前有$前缀。 $前缀在这里是Angular提供服务的名字空间,为了防止冲突,最好是避免你的服务和模型其他东西用 $开关。 如果你检查一个范围,你可能注意有些属性是用 $$开关,这些属性是被认为是私有,不能被读取或修改

注意最小化倍率

当Angular从控制器构建方法的参数名字中推导控制器的依赖,如果你 压缩 PhoneListCtrl的JavaScript代码,所有的方法参数都会压缩良好,依赖注入器可能不能正确识别服务。 我们能用依赖的名字的注解来避免这个问题,注解提供的字符串不会被最小化,这里有两种方法提供注入注解。

  • 在控制器中,创建一个持有一个字符数组的$inject属性,数组中的每个字符串是对应于要注入服务的参数的名字,在我们的例子中可以这么写:

    functionPhoneListCtrl($scope,$http){...}
    PhoneListCtrl.$inject=['$scope','$http'];
    phonecatApp.controller('PhoneListCtrl',PhoneListCtrl);
  • 使用一行注解,代替我们刚刚提供的方法,你提供一个数组,数组包括服务名称的列表,后面跟着函数

    functionPhoneListCtrl($scope,$http){...}
    phonecatApp.controller('PhoneListCtrl',['$scope','$http',PhoneListCtrl]);

两种方法都可以通过Angular给任何函数注入,所以选择那个决定于你的工程风格。 当我们使用第二种方法,常用方法是当注入控制器时在一行内提供匿名函数构建器。

phonecatApp.controller('PhoneListCtrl',$http){...}]);

从这点出发,我们将在教程中使用行内方法,用这种意图,让我们增加一个注解给我们的 PhoneListCtrl app/js/controllers.js:

varphonecatApp=angular.module('phonecatApp',$http){
$http.get('phones/phones.json').success(function(data){
$scope.phones=data;
});

$scope.orderProp='age';
}]);

测试

test/unit/controlleRSSpec.js: 因为我们开始使用依赖注入,并且我们的控制器有了依赖,构造控制器在我们测试中有一点复杂,我们使用new操作符,提供有某些假$http实现的控制器,但是 Angular提供模拟$http服务,我们能用他来做单元测试,我们配置“假”响应服务通过调用服务上的方法,服务响应。

describe('PhoneCatcontrollers',function(){

describe('PhoneListCtrl',function(){
varscope,ctrl,$httpBackend;

//LoadourappmoduledeFinitionbeforeeachtest.
beforeEach(module('phonecatApp'));

//Theinjectorignoresleadingandtrailingunderscoreshere(i.e._$httpBackend_).
//Thisallowsustoinjectaservicebutthenattachittoavariable
//withthesamenameastheserviceinordertoavoidanameconflict.
beforeEach(inject(function(_$httpBackend_,$rootScope,$controller){
$httpBackend=_$httpBackend_;
$httpBackend.expectGET('phones/phones.json').
respond([{name:'NexusS'},{name:'MotorolaDROID'}]);

scope=$rootScope.$new();
ctrl=$controller('PhoneListCtrl',{$scope:scope});
}));

注意:因为在我们的测试环境中读取Jasmin和angular-mocks.js,我们用两个帮助方法 moduleinject来读取各配置注入器。 我们在测试环境中创建控制器,如下:

  • 我们使用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('shouldcreate"phones"modelwith2phonesfetchedfromxhr',function(){
expect(scope.phones).toBeUndefined();
$httpBackend.flush();

expect(scope.phones).toEqual([{name:'NexusS'},{name:'MotorolaDROID'}]);
});
  • 在浏览器中,我们通过调用$httpBackend.flush()刷入请求队列,这样通过$http服务用准备好的response产生promise的返回值。在mock $httpBackend文档中看‘刷入Http请求’,解释为什么这是必须的。

  • 我们创建断言,验证手机模型现在存在有scope中。

最后,我们验证orderProp认值设定正确。

it('shouldsetthedefaultvalueoforderPropmodel',function(){
expect(scope.orderProp).toBe('age');
});

现在你可以在Karma选项卡中查看下面的输出

Chrome22.0:Executed2of2SUCCESS(0.028secs/0.007secs)

实验

在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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐