bigblind
bigblind

Reputation: 12887

What's the best way to implement events to communicate between services and anything else?

So let's say I have a controler that dppends on a news service. Whenever news is published, the controller would like to diisplay the latest news. I'd rather not use $broadcast and $on, because this does weird things to the way components are coupled. Components which don't depend on news could still listen for these events.

So, here's what I'd like to be able to do:

myApp.controller("myController", ["news", function(news){
    news.onPublish.addListener(function(story){
        ... Show the latest juicy story.
    });
}]);

news.onPublish would be an Event instance, with Event defined as follows:

Event = function(){
  var listeners = [];

  this.addListener = function(l){
    listeners.push(l);
  }

  this.trigger = function(){
    var params = arguments
    listeners.map(function(l){
      l.apply(undefined, params);
    });
  }

  return this
}

Is this a good way to implement communication between services and other components? Also, would it be good to call $rootScope.$apply at the end of Event.trigger so that any changes the listeners made will be picked up?

Upvotes: 1

Views: 126

Answers (1)

Idkt
Idkt

Reputation: 2996

The best is to write common data storing factories that do the job for you. Here's a working example: http://jsfiddle.net/9L5xL8sx/ which shows how this works. The NewsService factory can be used across several Angular modules, and within the same module, as shown in my example.

Here's the JS:

var app = angular.module("TestSharing", []);

app.factory("NewsService", [function() {
    var articles = [];
    var makeNews = function (text) {
        articles.push({text: text});
    };
    var getNews = function() {
        return articles;
    };
    return {
        get: getNews,
        make: makeNews 
    };
}]);

app.controller("FirstCtrl", ["$scope", "NewsService", function($scope, NewsService) {
    $scope.articles = function () {
        return NewsService.get();
    };
}]);

app.controller("SecondCtrl", ["$scope", "NewsService",  function($scope, NewsService) {
    $scope.articletext = "";
    $scope.submit = function () {
        NewsService.make($scope.articletext);
    };
}])

The HTML:

<div ng-app="TestSharing">
    <div ng-controller="FirstCtrl">
        <span ng-repeat="article in articles()">{{article.text}}<br/></span>
    </div>
    <div ng-controller="SecondCtrl">
        <input type="text" ng-model="articletext"/>
        <button ng-click="submit()">Make some news</button>
    </div>
</div>

Also, services like these can also share events. For example, if you'd used the factory to expose an object called somethingNew, which merely contained if something new had happened in one of the Controllers it had been shared in, you could achieve the same effect. The idea would be to only listen for changes where you'd want (using something like $scope.$watch(NewsService.somethingNew, function (now, then) {…})) and that would be just as easy.

Upvotes: 1

Related Questions