angularjs教程

详解AngularJS的通信机制

时间:2015-08-07 16:07来源:网络整理 作者:KKWL 点击:
现在几乎满世界的人都在问! 外面有人么? 这里是 USS AngularJS, 我们遇到麻烦了,我们的服务讲得是克灵贡语(Klingon) 而我们的控制器不能同它们的Ferengi 指令通信了. 有人能帮助我们么

 

现在几乎满世界的人都在问! 外面有人么? 这里是 USS AngularJS, 我们遇到麻烦了,我们的服务讲得是克灵贡语(Klingon) 而我们的控制器不能同它们的Ferengi 指令通信了. 有人能帮助我们么!

我已经不知道有多少次遇到这种有关什么才是AngularJS里面的组件通信的最佳方式这样的问题了. 很多时候答案都会是为此使用 $rootScope 对象去向任何想要收听的人广播$broadcast出一条消息. 然而,那还真不是做这件事的最佳方式. 组件之间广播消息意味着它们需要多少知道一些其它组件编码的细节,这样就限制了它们的模块化和重用.中国学网 中 国 学 网 ww w.x u 1 6 3.co m

本文我就将展示如何为AngularJS中的内部组件通信使用发布/订阅模式.


AngularJS 有多种方式可供你用于组件之间的通信,而最常使用的方法却需要你知道太多有关那些组件如何通信的细节,这样就增加了组件之间的耦合度,并降低了它们的模块性和内聚程度. 这样也就使得你的组件很难在其它应用程序中重用.

通过使用发布/订阅设计模式,我们可以降低组件之间的耦合度,并将它们的之间通信的细节封装起来. 这将能帮助增加你组件的模块化程度,可测试性以及可重用性.

我将会描述的发布/订阅模式实现由 Eric Burley, @eburley 在它的帖子angularjs.org 观察, 有关发布订阅模式.. 中推荐过。

我所描述的示例应用程序,会向你展示你可以将发布/订阅模式如何运用于内部控制器通信以及控制器的服务通信. 你可以在GitHub上我的资源库 angularjs-pubsub 下面找到源代码.
 
首先我们需要一条通信管道

首先我们来讲讲用于处理发布和订阅信息的服务。我定义了一个服务接口,提供了发布和订阅信息的方法,我们可以用它来处理我们想要用来交换的信息。

在下面的代码中,我定义了两个内部信息; _EDIT_DATA_, 用来表示我们需要编辑跟随信息传过来的数据,和 _DATA_UPDATED_, 用来表示我们的数据已经被改变。这些都是定义在内部的,用户没办法访问到它们的,这样有助于隐藏具体实现。

而对于每条信息,有两个方法; 一个用来发布信息推送给订阅者,另一个可以让订阅者注册一个回调方法,当接收到信息的时候,这个方法就会被调用。


用来向订阅者发布信息方法是 editData,在第 9 行,还有 dataUpated,在第 19 行。它们通过 $rootScope.$broadcast 方法向待处理事件推送私有通知。

用来注册事件的方法,通过 $scope.$on 建立监听,当接收到广播的消息之后,就会轮流执行那些被订阅者注册到服务上的事件。同时,由于订阅者需要自己的 scope 作为参数传过来,我们可以用它来执行监听的信息,从而避免了维护监听者列表这些复杂的处理。注册事件的方法是 onEditData,在 13 行,还有 onDataUpdated 在 23 行。

为了隐藏实现细节,我用了 Revealing Module (揭示模块:好丑的名字)模式,只返回那些我希望让用户使用的方法。
 

angular.module(['application.services']) // define the request notification channel for the pub/sub service .factory('requestNotificationChannel', ['$rootScope', function ($rootScope) { // private notification messages var _EDIT_DATA_ = '_EDIT_DATA_'; var _DATA_UPDATED_ = '_DATA_UPDATED_'; // publish edit data notification var editData = function (item) { $rootScope.$broadcast(_EDIT_DATA_, {item: item}); }; //subscribe to edit data notification var onEditData = function($scope, handler) { $scope.$on(_EDIT_DATA_, function(event, args) { handler(args.item); }); }; // publish data changed notification var dataUpdated = function () { $rootScope.$broadcast(_DATA_UPDATED_); }; // subscribe to data changed notification var onDataUpdated = function ($scope, handler) { $scope.$on(_DATA_UPDATED_, function (event) { handler(); }); }; // return the publicly accessible methods return { editData: editData, onEditData: onEditData, dataUpdated: dataUpdated, onDataUpdated: onDataUpdated }; }])

发布消息

发布消息很简单,首先我们需要在我们的控制器里为 requestNotificationChannel 引入一些依赖. 你可以在下面dataService的定义第二行看到这个. 当事件发生时,如果需要向需要了解有变化发生的其它对象发送信号, 你只需要调用requestNotificationChannel上恰当的通知方法就可以了. 如果你注意到了dataService的 saveHop, deleteHop 和 addHop 方法, 你就会看到它们都调用了 requestNotificationChannel 上的dataUpdated方法, 这个方法将会给侦听器发送信号,侦听器则已经用 onDataUpdated 方法注册过了.

// define the data service that manages the data .factory('dataService', ['requestNotificationChannel', function (requestNotificationChannel) { // private data var hops = [ { "_id": { "$oid": "50ae677361d118e3646d7d6c"}, "Name": "Admiral", "Origin": "United Kingdom", "Alpha": 14.75, "Amount": 0.0, "Use": "Boil", "Time": 0.0, "Notes": "Bittering hops derived from Wye Challenger. Good high-alpha bittering hops. Use for: Ales Aroma: Primarily for bittering Substitutions: Target, Northdown, Challenger", "Type": "Bittering", "Form": "Pellet", "Beta": 5.6, "HSI": 15.0, "Humulene": 0.0, "Caryophyllene": 0.0, "Cohumulone": 0.0, "Myrcene": 0.0, "Substitutes": ""} , { "_id": { "$oid": "50ae677361d118e3646d7d6d"}, "Name": "Ahtanum", "Origin": "U.S.", "Alpha": 6.0, "Amount": 0.0, "Use": "Boil", "Time": 0.0, "Notes": "Distinctive aromatic hops with moderate bittering power from Washington. Use for: Distinctive aroma Substitutes: N/A", "Type": "Aroma", "Form": "Pellet", "Beta": 5.25, "HSI": 30.0, "Humulene": 0.0, "Caryophyllene": 0.0, "Cohumulone": 0.0, "Myrcene": 0.0, "Substitutes": ""} , { "_id": { "$oid": "50ae677361d118e3646d7d6e"}, "Name": "Amarillo Gold", "Origin": "U.S.", "Alpha": 8.5, "Amount": 0.0, "Use": "Boil", "Time": 0.0, "Notes": "Unknown origin, but character similar to Cascade. Use for: IPAs, Ales Aroma: Citrus, Flowery Substitutions: Cascade, Centennial", "Type": "Aroma", "Form": "Pellet", "Beta": 6.0, "HSI": 25.0, "Humulene": 0.0, "Caryophyllene": 0.0, "Cohumulone": 0.0, "Myrcene": 0.0, "Substitutes": ""} , { "_id": { "$oid": "50ae677361d118e3646d7d6f"}, "Name": "Aquila", "Origin": "U.S.", "Alpha": 6.5, "Amount": 0.0, "Use": "Boil", "Time": 0.0, "Notes": "Aroma hops developed in 1988. Limited use due to high cohumolone.Used for: Aroma hops Substitutes: ClusterNo longer commercially grown.", "Type": "Aroma", "Form": "Pellet", "Beta": 3.0, "HSI": 35.0, "Humulene": 0.0, "Caryophyllene": 0.0, "Cohumulone": 0.0, "Myrcene": 0.0, "Substitutes": ""} , { "_id": { "$oid": "50ae677361d118e3646d7d70"}, "Name": "Auscha (Saaz)", "Origin": "Czech Republic", "Alpha": 3.3, "Amount": 0.0, "Use": "Boil", "Time": 0.0, "Notes": " Use for: Pilsners and Bohemian style lagers Aroma: Delicate, mild, clean, somewhat floral -- Noble hops Substitute: Tettnanger, LublinExamples: Pulsner Urquell", "Type": "Aroma", "Form": "Pellet", "Beta": 3.5, "HSI": 42.0, "Humulene": 0.0, "Caryophyllene": 0.0, "Cohumulone": 0.0, "Myrcene": 0.0, "Substitutes": ""} , ]; // sends notification that data has been updated var saveHop = function(hop) { requestNotificationChannel.dataUpdated(); }; // removes the item from the array and sends a notification that data has been updated var deleteHop = function(hop) { for(var i = 0; i < hops.length; i++) { if(hops[i]._id.$oid === hop._id.$oid) { hops.splice(i, 1); requestNotificationChannel.dataUpdated(); return; } }; }; // internal function to generate a random number guid generation var S4 = function() { return (((1+Math.random())*0x10000)|0).toString(16).substring(1); }; // generates a guid for adding items to array var guid = function () { return (S4() + S4() + "-" + S4() + "-4" + S4().substr(0,3) + "-" + S4() + "-" + S4() + S4() + S4()).toLowerCase(); }; // function to add a hop to the array and sends a notification that data has been updated var addHop = function(hop) { hops.id.$oid = guid(); hops.push(hop); requestNotificationChannel.dataUpdated(); }; // returns the array of hops var getHops = function() { return hops; }; // returns a specific hop with the given id var getHop = function(id) { for(var i = 0; i < hops.length; i++) { if(hops[i]._id.$oid === id) { return hops[i]; } }; }; // return the publicly accessible methods return { getHops: getHops, getHop: getHop, saveHop: saveHop, deleteHop: deleteHop, addHop: addHop } }]);


接收事件通知

------分隔线----------------------------