Hampir semua orang di seluruh dunia bertanya sekarang! Adakah sesiapa di luar sana? Ini USS AngularJS, kami menghadapi masalah, perkhidmatan kami bercakap Klingon dan pengawal kami tidak dapat berkomunikasi dengan mereka
Saya tidak dapat memberitahu anda berapa kali saya telah ditanya soalan ini tentang cara terbaik untuk komponen berkomunikasi dalam AngularJS Banyak kali jawapannya ialah menggunakan objek $rootScope untuk mencapai sesiapa sahaja yang ingin mendengar . Menyiarkan $menyiarkan mesej Walau bagaimanapun, itu bukan cara terbaik untuk melakukan ini. Menyiarkan mesej antara komponen bermakna mereka perlu mengetahui beberapa butiran pengekodan komponen lain, yang mengehadkan modulariti dan penggunaan semula.Dalam artikel ini saya akan menunjukkan kepada anda cara menggunakan corak terbitkan/langganan untuk komunikasi komponen dalaman dalam AngularJS.
AngularJS mempunyai banyak cara yang boleh anda gunakan untuk berkomunikasi antara komponen, tetapi kaedah yang paling biasa digunakan memerlukan anda mengetahui terlalu banyak butiran tentang cara komponen tersebut berkomunikasi, yang meningkatkan gandingan antara komponen dan mengurangkan modulariti dan kohesinya Ini menjadikannya sukar untuk digunakan semula komponen anda dalam aplikasi lain.
Pelaksanaan corak terbitkan/langganan yang akan saya huraikan telah disyorkan oleh Eric Burley, @eburley dalam siarannya
Pemerhatian angularjs.org, Mengenai corak terbitkan/langganan.. .
Aplikasi contoh yang saya terangkan akan menunjukkan kepada anda bagaimana anda boleh menggunakan corak terbitkan/langganan untuk komunikasi pengawal dalaman dan komunikasi perkhidmatan pengawal Anda boleh menemuinya dalam repositori saya di GitHubangularjs- pubsub Cari sumbernya. kod di bawah.
Mula-mula kita memerlukan saluran komunikasi
Dalam kod di bawah, saya mentakrifkan dua mesej dalaman; _EDIT_DATA_, untuk menunjukkan bahawa kami perlu mengedit data yang dihantar bersama dengan mesej, dan _DATA_DATA_DATA_, untuk menunjukkan bahawa data kami telah ditukar. Ini ditakrifkan secara dalaman dan tidak boleh diakses oleh pengguna, yang membantu menyembunyikan pelaksanaan.
Untuk setiap maklumat, terdapat dua kaedah; satu digunakan untuk menerbitkan maklumat dan menolaknya kepada pelanggan, dan satu lagi membenarkan pelanggan mendaftar kaedah panggilan balik, yang akan dipanggil apabila maklumat diterima.
Kaedah yang digunakan untuk menerbitkan maklumat kepada pelanggan ialah editData, pada baris 9, dan dataUpated, pada baris 19. Mereka menolak pemberitahuan peribadi ke acara yang belum selesai melalui kaedah $rootScope.$broadcast.
Untuk menyembunyikan butiran pelaksanaan, saya menggunakan pola Modul Pendedahan (modul mendedahkan: nama hodoh) untuk hanya mengembalikan kaedah yang saya mahu pengguna gunakan.
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 }; }])
Siarkan mesej
Menerbitkan mesej adalah mudah, mula-mula kami perlu memperkenalkan beberapa kebergantungan untuk requestNotificationChannel dalam pengawal kami Anda boleh melihat ini dalam baris kedua takrifan dataService di bawah berlaku, Untuk menghantar isyarat kepada objek lain, anda hanya perlu memanggil kaedah pemberitahuan yang sesuai pada requestNotificationChannel Jika anda melihat kaedah saveHop, deleteHop dan addHop dataService, anda akan melihat bahawa mereka semua memanggil kaedah dataUpdated pada kaedah requestNotificationChannel ini isyarat akan dihantar kepada pendengar, yang telah didaftarkan menggunakan kaedah 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 } }]);
接收事件通知
从 requestNotificationChannel 接收事件通知也很简单,额外的我们只需要回调处理器来在消息被发送时使用通知来做一些自己的处理. 我们将再次需要添加一些依赖到面向我们的控制器、服务以及指令的 requestNotificationChannel 上, 你可以在下面代码的第二行中看到这些. 接下来我们需要定义一个事件回调处理器来对事件通知做出回应,你可以在下面的第五行代码中看到. 然后我们需要通过调用 onDataUpdated 方法来吧我们的回调处理器注册到requestNotificationChannel,并传入来自控制器和回调处理器的范围, 我们在第9行代码中做了这些事情.
//define the controller for view1 .controller('view1-controller', ['$scope', 'dataService', 'requestNotificationChannel', function($scope, dataService, requestNotificationChannel) { $scope.hops = dataService.getHops(); var onDataUpdatedHandler = function() { $scope.hops = dataService.getHops(); } requestNotificationChannel.onDataUpdated($scope, onDataUpdatedHandler); $scope.onEdit = function(hop) { requestNotificationChannel.editData(hop); } $scope.onDelete = function(hop) { dataService.deleteHop(hop); } }]);
用于控制器通信的控制器
我们也可以将 the requestNotificationChannel 用于控制器间的通信. 我们只需要有一个控制器扮演发布者的角色,而另外一个控制器扮演订阅者的角色就行了. 如果你观察到前段代码第11行view1-controller的onEdit方法,你会看到它发送了一个editData消息,消息包含需要使用 requestNotificationChannel 编辑的项. 下面的 view2-controller 从第5行到第9行将它的 onEditDataHandler 用 requestNotificationChannel 进行了注册. 如此无论何时view1-controller一旦发送editData消息,带上要修改的项,view2-controller都会受到editData消息的通知,获得该项并将其更新到它的模型.
//define the controller for view1 .controller('view2-controller', ['$scope', 'dataService', 'requestNotificationChannel', function($scope, dataService, requestNotificationChannel) { $scope.hop = null; var onEditDataHandler = function(item) { $scope.hop = item; }; requestNotificationChannel.onEditData($scope, onEditDataHandler); $scope.onSave = function() { dataService.saveHop($scope.hop); $scope.hop = null; } $scope.onCancel = function() { $scope.hop = null; } }]);
写一个好的接口文档
有一件事情可能会被忽略,我们在组件间用了通信接口,而这些接口,它们需要一个好的文档来说明应当如何使用。上面的例子中,如果没有文档,用户肯定不会知道 onEditData 会给回调函数传一个待编辑数据。所以当你开始用这个模式,用好的技巧在于,给方法写注释文档,以确保通知服务明确知道发生了什么事情。
总结
好了,我们探讨了如何在你的 AngularJS 应用中使用订阅/发布模式来实现模块间通信。该模式可以让你的模块从内部消息解耦,更便于复用。你甚至可以把模块之间的通信全部替换成订阅/发布模式。尤其当你的服务中有很多异步请求,以及你希望把数据缓存在服务中,从而减少和服务器通信的时候,这种模式相当有效。
我希望这对你有所帮助,你可以在我的 GitHub 仓库 angularjs-pubsub 下找到例子的代码。