MVC中,为了方便维护,针对不同业务会使用不同的controller。有时我们需要在不同的controller中共享数据,本文旨在解决这一问题。

1. 使用$rootScope直接绑定

AngularJS中有一个$rootScope对象,它是AngularJS中最接近全局作用域的对象,是所有$scope对象的最上层,可以简单理解为BOM中的window对象或Node.js中的global对象。最简单的方式是直接将要共享的数据绑定到$rootScope对象中:

<!DOCTYPEhtml><htmlng-app="exampleApp"><head><metacharset="utf-8"><title>ShareBetweenCtrls</title><scriptsrc="lib/angular.js"></script><linkhref="css/bootstrap.min.css"rel="stylesheet"/><linkrel="stylesheet"href="css/bootstrap-responsive.min.css"><script>varapp=angular.module("exampleApp",[]);app.controller("FirstController",function($rootScope,$scope){$scope.shareObject=function(obj){$rootScope.person=obj||{};};});app.controller("SecondController",function($rootScope,$scope){$scope.reportData=function(){varreportString="",person=$rootScope.person||{};for(variinperson){reportString+="person's"+i+"is"+person[i]+"\n";}alert(reportString);};});</script></head><body><divclass="well"ng-controller="FirstController"><inputtype="text"ng-model="person.name"placeholder="InputYourName"/><inputtype="text"ng-model="person.age"placeholder="InputYourAge"/><inputtype="text"ng-model="person.sex"placeholder="InputYourSex"/><buttonclass="btnbtn-primary"ng-click="shareObject(person)">ShareData</button></div><divclass="well"ng-controller="SecondController"><buttonclass="btnbtn-primary"ng-click="reportData()">ReportData</button></div></body></html>

整个效果如图-1 ~ 图-4所示:

图-1 页面加载完毕

图-2 第一次点击"Report Data"按钮

图-3 填写信息,点击"Share Data"按钮

图-4 再次点击"Report Data"按钮

这样做解决了问题,在需要共享的数据量较少时可以采用,但因为会污染全局作用域,因此十分不推荐使用这种方法。

2. 使用service共享数据

...<script>varapp=angular.module("exampleApp",[]);//需要将DataShareService注入app.controller("FirstController",function($scope,DataShareService){$scope.person={};$scope.shareObject=function(obj){//赋值DataShareService.shareObject=obj;};});//需要将DataShareService注入app.controller("SecondController",function($scope,DataShareService){varperson={};$scope.reportData=function(){varreportString="",person=DataShareService.shareObject;//取值for(variinperson){reportString+="person's"+i+"is"+person[i]+"\n";}alert(reportString);};});//自定义service,在多个controller之间共享数据app.service("DataShareService",function(){//无需定义其他变量,无需return,如果使用factory()则至少需要return一个空对象});<!--这里的app.factory()可以替换为app.constant()app.value()app.service()--></script>...

最终实现的效果和使用$rootScope直接绑定完全相同,优点是解决了全局作用域被污染问题。有关最后app.factory()的替换问题可以参考之前的一篇博客,使用AngularJS自定义service,有兴趣的读者可以自己试验一下。

3. 使用$scope事件机制

$scope可以向其他$scope广播或发送事件,其他$scope监听事件并处理,从而实现通信,也就是说可以通过$scope事件机制实现不同controller之间的数据共享。$scope事件机制包括以下三种方法:

表-1 有关$scope事件机制的三个方法

其中,$broadcast(name, args)为父级$scope向子级$scope发送事件,$emit(name, args)为子级$scope向父级$scope发送事件,$on(name, handler)为监听事件的函数,handler参数为对事件进行处理的函数,该函数包含两个参数:event和args,分别为事件对象和发送事件时传递的args参数。

这里我们不存在controller的嵌套,所有的$scope为同级,需要使用“祖宗级”$rootScope进行广播。有关controller嵌套和继承的问题会在之后的博文中讲到。

使用$scope事件机制处理数据共享的JS代码如下所示,由于HTML代码与之前相同,故省略:

...<script>varapp=angular.module("exampleApp",[]);app.controller("FirstController",function($rootScope,$scope){$scope.person={};$scope.shareObject=function(obj){obj=obj||{};//将事件以"ShareObjectEvent"为名进行广播$rootScope.$broadcast("ShareObjectEvent",obj);};});app.controller("SecondController",function($scope){//监听"ShareObjectEvent"事件$scope.$on("ShareObjectEvent",function(event,args){person=args;});$scope.reportData=function(){varreportString="";for(variinperson){reportString+="person's"+i+"is"+person[i]+"\n";}alert(reportString);};});</script>...

最终实现的效果和使用$rootScope直接绑定完全相同。

最后需要补充的一点是,使用$scope事件机制与前两种方法相比有着实时性的优势,即数据的变化能够及时被响应,如果想在使用前两种方法时达到监听数据变化实时响应的效果,需要用到AngularJS的$watch$watchCollection功能,详情请参考这里。

完。