Skip to content

Instantly share code, notes, and snippets.

@turtlemonvh
Last active January 3, 2021 16:37
Show Gist options
  • Star 26 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save turtlemonvh/10686980 to your computer and use it in GitHub Desktop.
Save turtlemonvh/10686980 to your computer and use it in GitHub Desktop.
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
Copy link
Author

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
Copy link
Author

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
Copy link

Thank you!

@williscool
Copy link

+1

@alopes
Copy link

alopes commented May 21, 2014

Thanks! :)

@catalyst156
Copy link

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
Copy link

Thanks! for many searching , this is the best solution

@ralphv
Copy link

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
Copy link

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