> ## Content Index
> Fetch the complete content index at: https://www.jonathancreamer.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# An angular.js event bus with postal.js
- URL: https://www.jonathancreamer.com/an-angular-event-bus-with-postal-js/
- Published: 2014-04-30T19:01:23.000Z
- Updated: 2014-05-06T16:40:53.000Z
- Author: Jonathan Creamer
- Tags: javascript, postal.js, angularjs, events

Ideally in an angular application, controllers are independent units of code that have no reference to any other controllers. There are cases though in which you may need to communicate with other controllers in your application. For example you may have an `Orders` controller, that needs to tell a `Cart` controller that a new item has been added.

One of the best ways of accomplishing this type of communication is through the use of an event bus.

My favorite event bus framework is [postal.js](http://github.com/postaljs/postal.js?ref=jonathancreamer.com).

### What is it?

> Postal.js is an in-memory message bus - very loosely inspired by AMQP - written in JavaScript. Postal.js runs in the browser, or on the server-side using Node.js. It takes the familiar "eventing-style" paradigm (of which most JavaScript developers are familiar) and extends it by providing "broker" and subscriber implementations which are more sophisticated than what you typically find in simple event delegation.

You can use postal by publishing messages accross specific channels. In this way you can segregate your messages to things like `app`, `cart`, `ui`, etc. It also uses an *envelope* pattern to prevent having **n** arguments in your subscription callbacks.

Using postal.js, you can easily decorate the `$scope` and add a `$bus` that will allow you to communicate with other controllers in your application.

```prettyprint
angular.module('myApp')
    .config(function ($provide) {
        $provide.decorator('$rootScope', [
        	'$delegate', function ($delegate) {
            Object.defineProperty($delegate.constructor.prototype, 
            '$bus', {
                value: postal,
                enumerable: false
            });

            return $delegate;
        }]);
    });

```

Now in your controllers you have postal available as `$scope.$bus`...

```prettyprint
'use strict';

angular.module('myApp')
    .controller('CartCtrl', ['$scope', function ($scope) {
        $scope.$bus.subscribe({
            channel: 'orders',
            topic: 'order.new',
            callback: function(data, envelope) {
                console.log('it worked', data, evenlope);
            }
        });
    }
])
	.controller('OrderCtrl', ['$scope', function ($scope) {
        $scope.order = function() {
        	$scope.$bus.publish({
              channel: 'orders',
              topic: 'order.new',
              data: { /* order info */ }
          });
        };
    }
]);

```

In the `CartCtrl`, the `$scope.$bus.subscribe` method is called. This subscription gets set up to listen on the `orders` channel for any messages with the `order.new` topic. When a message comes throught that matches that topic, the `callback` will be invoked.

In the `OrderCtrl`, the `$scope.$bus.publish` method is called whenever `$scope.order` is called. This publishes a message on the right channel, with the right topic that will trigger the subscription. The `data` sent via the publish will be recieved in the `callback` of the subscription, as well as an `envelope`, which is a wrapper around the data.

### Conclusion

Using the `$bus` decorator makes communicating with other controllers extremely simple. Of course you can use any messaging framework you'd like. If you'd like to learn more about postal, check out the repo, clone it, and feel free to give [Jim Cowart](http://twitter.com/ifandelse?ref=jonathancreamer.com) some love for making such a great library!

## UPDATE 5/6/14

A commenter pointed out that there's a potential memory leak since controller instances are created multiple times. I went in and took a look and added some code to listen to the `$destroy` event on the scope and call unsubscribe.

```prettyprint
angular.module('introToAngularApp')
.config(function ($provide) {
    $provide.decorator('$rootScope', ['$delegate', function ($delegate) {
        Object.defineProperty($delegate.constructor.prototype, '$bus', {
            get: function() {
                var self = this;

                return {
                    subscribe: function() {
                        var sub = postal.subscribe.apply(postal, arguments);

                        self.$on('$destroy',
                        function() {
                            sub.unsubscribe();
                        });
                    },
                    channel: postal.channel,
                    publish: postal.publish
                };
            },
            enumerable: false
        });

        return $delegate;
    }]);
});

```

I had to use the `get` of `Object.defineProperty` so that I can have a hold of the correct `this` for the `$on`. Then it simply listens for that event, and calls `sub.unsubscribe()`.

That should help alleviate any memory leak problems!