简体   繁体   English

AngularJS:通过服务在两个示波器/控制器之间进行双向通信

[英]AngularJS: bi-directional communication between two scopes/controllers via a service

I have quite a few scenarios where I need clicks, etc. to trigger behavior in another place on the page (a one-way communication scenario). 我有很多情况需要点击等来触发页面另一位置上的行为(单向通信情况)。 I now have a need for bi-directional communication, where stuff that happens in element A can modify specific properties in the scope behind element B and vice-versa. 我现在需要双向通信,其中元素A中发生的事情可以修改元素B后面范围内的特定属性,反之亦然。 Thus far, I've been using $rootScope.$broadcast to facilitate this but it feels like overkill, and winds up creating boilerplate in both places: 到目前为止,我一直在使用$rootScope.$broadcast来简化此操作,但感觉有点过头了,最后在两个地方都创建了样板:

$scope.$on('event-name', function(event, someArg) {
    if(someArg === $scope.someProperty) return;

    $scope.someProperty = someArg;
});

$scope.$watch('someProperty', function(newValue) {
    $rootScope.$broadcast('event-name', newValue);
});

Is there a better way? 有没有更好的办法? I'd like to tie the two (or three, or N) scopes together via a service, but I don't see a way to do that without magic event names and boilerplate. 我想通过服务将两个(或三个或N个)作用域联系在一起,但是我没有一种没有魔术事件名称和样板的方法。

I haven't used this myself, but this post explains basically how I would do it. 我自己没有使用过,但是这篇文章基本上解释了我将如何使用它。 Here's the code which illustrates the idea: 这是说明此想法的代码

(function() {
    var mod = angular.module("App.services", []);

    //register other services here...

    /* pubsub - based on https://github.com/phiggins42/bloody-jquery-plugins/blob/master/pubsub.js*/
    mod.factory('pubsub', function() {
        var cache = {};
        return {
            publish: function(topic, args) { 
                cache[topic] && $.each(cache[topic], function() {
                    this.apply(null, args || []);
                });
            },

            subscribe: function(topic, callback) {
                if(!cache[topic]) {
                    cache[topic] = [];
                }
                cache[topic].push(callback);
                return [topic, callback]; 
            },

            unsubscribe: function(handle) {
                var t = handle[0];
                cache[t] && d.each(cache[t], function(idx){
                    if(this == handle[1]){
                        cache[t].splice(idx, 1);
                    }
                });
            }
        }
    });


    return mod;
})();

Note the memory leak though if controllers are "deleted" without unsubscribing. 请注意,如果在不取消订阅的情况下“删除了”控制器,则会发生内存泄漏。

I think you can try the following service, 我认为您可以尝试以下服务,

 'use strict'; angular.module('test') .service('messageBus', function($q) { var subscriptions = {}; var pendingQuestions = []; this.subscribe = function(name) { subscriptions[name].requestDefer = $q.defer(); return subscriptions[name].requestDefer.promise; //for outgoing notifications } this.unsubscribe = function(name) { subscriptions[name].requestDefer.resolve(); subscriptions[name].requestDefer = null; } function publish(name, data) { subscriptions[name].requestDefer.notify(data); } //name = whom shd answer ? //code = what is the question ? //details = details abt question. this.request = function(name, code, details) { var defered = null; if (subscriptions[name].requestDefer) { if (pendingQuestions[code]) { //means this question is already been waiting for answer. //hence return the same promise. A promise with multiple handler will get //same data. defered = pendingQuestions[code]; } else { defered = $q.defer(); //this will be resolved by response method. pendingQuestions[code] = defered; //asking question to relevant controller publish(name, { code: code, details: details }); } } else { //means that one is not currently in hand shaked with service. defered = $q.defer(); defered.resolve({ code: "not subscribed" }); } return defered.promise; } //data = code + details //responder does not know the destination. This will be handled by the service using //pendingQuestions[] array. or it is preemptive, so decide by code. this.response = function(data) { var defered = pendingQuestions[data.code]; if (defered) { defered.resolve(data); } else { //means nobody requested for this. handlePreemptiveNotifications(data); } } function handlePreemptiveNotifications() { switch (data.code) { //handle them case by case } } }); 

This can be used as a message bus in multi controller communication. 可用作多控制器通信中的消息总线。 It is making use of the angular notify() callback of promise API.All the participating controllers should subscribe the service as follows, 它使用了promise API的angular notify()回调。所有参与的控制器应按以下方式订阅服务,

 angular.module('test') .controller('Controller1', function($scope, messageBus) { var name = "controller1"; function load() { var subscriber = messageBus.subscribe(name); subscriber.then(null, null, function(data) { handleRequestFromService(data); }); } function handleRequestFromService(data) { //process according to data content if (data.code == 1) { data.count = 10; messageBus.respond(data); } } $scope.$on("$destroy", function(event) { //before do any pending updates messageBus.unsubscribe(name); }); load(); }); angular.module('test') .controller('Controller2', function($scope, messageBus) { var name = "controller2"; function load() { var subscriber = messageBus.subscribe(name); subscriber.then(null, null, function(data) { handleRequestFromService(data); }); } function handleRequestFromService(data) { //process according to data content } $scope.getHorseCount = function() { var promise = messageBus.request("controller1", 1, {}); promise.then(function(data) { console.log(data.count); }); } $scope.$on("$destroy", function(event) { //before do any pending updates messageBus.unsubscribe(name); }); load(); }); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM