2013-04-26 4 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

+0

'd.each' должно быть' $ .each' – Danita

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

Смежные вопросы