2013-04-26 47 views
0

我有相當多的場景需要點擊等來觸發頁面上另一個地方的行爲(單向通信場景)。我現在需要雙向通信,其中元素A中發生的事情可以修改元素B後面的範圍內的特定屬性,反之亦然。到目前爲止,我一直在使用$rootScope.$broadcast,以方便這一點,但感覺就像矯枉過正,並纏在兩地建立樣板:AngularJS:通過服務在兩個示波器/控制器之間進行雙向通信

$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); 
}); 

有沒有更好的辦法?我想通過服務將兩個(或三個或N個)示波器連接在一起,但我沒有辦法在沒有神奇事件名稱和樣板的情況下執行此操作。

回答

1

我自己沒有用過這個,但是this post基本解釋了我會怎麼做。 Here's the code它描述了一個思路:

(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; 
})(); 

注意內存泄漏但如果控制器「刪除」無退訂。

+0

有趣的......它基本上是同樣的事情使用事件,但沒有泡沫化和泡沫化(或沉沒?= P)。它減少了樣板的合理數量。 – FMM 2013-04-26 13:07:07

+0

'd.each'應該是'$ .each' – Danita 2013-07-08 16:05:32

0

我想你可以試試下面的服務,

'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 
 
     } 
 
    } 
 
    });

這可以被用作多控制器通信的消息總線。它是利用承諾的角度通知()回調的API.All參與控制器應該訂閱服務如下,

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(); 
 
    });