Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Angular Messaging
var MyApp = angular.module('MyApp');
MyApp.factory('msgBus', ['$rootScope', function($rootScope) {
var msgBus = {};
msgBus.emitMsg = function(msg, data) {
data = data || {};
$rootScope.$emit(msg, data);
};
msgBus.onMsg = function(msg, func, scope) {
var unbind = $rootScope.$on(msg, func);
if (scope) {
scope.$on('$destroy', unbind);
}
return unbind;
};
return msgBus;
}]);
@turtlemonvh

This comment has been minimized.

Copy link
Owner Author

@turtlemonvh turtlemonvh commented Apr 14, 2014

An edit of this answer on StackOverflow about the best way to do message passing in angular.

I extended the solution to:

  • allow the user to pass data with the message
  • make passing of scope optional so this can be used in services as well as controllers
  • return the unbind function so the user can do their own memory management
@turtlemonvh

This comment has been minimized.

Copy link
Owner Author

@turtlemonvh turtlemonvh commented Apr 14, 2014

Example of use

Binding in a controller

// Passing in $scope allows the service to clean up references for you automatically
msgBus.onMsg('config.changed', function(event, data) {
  $scope.power = data.power;
  $scope.mass = data.mass;
}, $scope);

Binding in a service

// You can call unbindItemRemoved to clear the reference to this service
// and prevent memory leaks
var unbindItemremoved = msgBus.onMsg('config.itemRemoved', respondToChangeInItems);

Emitting in a controller or a service

msgBus.emitMsg('config.itemAdded', {'id': getID()});
@WhatFreshHellIsThis

This comment has been minimized.

Copy link

@WhatFreshHellIsThis WhatFreshHellIsThis commented May 1, 2014

Thank you!

@williscool

This comment has been minimized.

Copy link

@williscool williscool commented May 15, 2014

+1

@alopes

This comment has been minimized.

Copy link

@alopes alopes commented May 21, 2014

Thanks! :)

@catalyst156

This comment has been minimized.

Copy link

@catalyst156 catalyst156 commented Jun 6, 2014

This is just what I needed. Thanks for sharing!

In case other's stumble upon this small issue, the function you register with the msgBus.onMsg() function can takes a 'scope' argument. However, you cannot access that argument within the function defined because the call to $rootScope.$emit() doesn't pass anything for a third argument (for obvious reasons). Therefore, if you want to access the scope variable, you'll have to make a separate reference to it for use within the callback function.

app.directiive(....) {
    ...
    link: function(scope, element, attrs) {
        var linkScope = scope;

        msgBus.onMsg('msg-to-watch', function(event, data, scope) {

            //scope.whatever;  <-- will return undefined
            linkScope.whatever;  // <-- accessible

        }
    }
}
@jinwei233

This comment has been minimized.

Copy link

@jinwei233 jinwei233 commented Jun 11, 2014

Thanks! for many searching , this is the best solution

@ralphv

This comment has been minimized.

Copy link

@ralphv ralphv commented Jul 3, 2014

This is how we approached this, basically we replaced the $rootScope.$on function with another that maintains the same functionality, but if it takes a third parameters (scope), it will attach a destroy event to it that automatically removed the rootScope event.

app.run(["$rootScope", function($rootScope) {
var _nop = function() {};
var _ref = $rootScope.$on;
$rootScope.$on = function(name, listener, scope) {
var unbind = _ref.call($rootScope, name, listener);
if(scope && unbind) {
scope.$on('$destroy', unbind);
return _nop;
}
return unbind;
}
}]);

@liekkas

This comment has been minimized.

Copy link

@liekkas liekkas commented Jul 9, 2015

thanks,very helpful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment