Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Provide $scope.$onRootScope method #4574

@cburgdorf

Description

@cburgdorf

Many people are afraid of using angulars event mechanism as an EventBus as they fear of performance issues because of it's bubbling behavior.

However, those concerns don't apply if only $rootScope.$emit/ $rootScope.$on is used as there is no bubbling happening since $emit only bubbles upwards and there is no scope above the $rootScope.

I addressed this in my answer on the same thread.

In fact if eventing is used like that in an angular application than $rootScope is no different than the typical EventBus pattern. This comes with the drawback of manually having to unregister handlers from within controllers. Why that? Because controllers aren't singletons in Angular and therefore one needs to listen to the local $scope's $destroy event and then unregister from the event emitted by the $rootScope.

So controller code would look like this:

angular
    .module('MyApp')
    .controller('MyController', ['$scope', '$rootScope', function MyController($scope, $rootScope) {

            var unbind = $rootScope.$on('someComponent.someCrazyEvent', function(){
                console.log('foo');
            });

            $scope.$on('$destroy', unbind);
        }
    ]);

As stated in my SO post one can monkey patch the $rootScope to provide an alternative to it's $on method that takes an additional parameter with an $scope to listen for it's $destroy event to then do the deregistration for us.

 angular
    .module('MyApp')
    .config(['$provide', function($provide){
        $provide.decorator('$rootScope', ['$delegate', function($delegate){

            $delegate.$saveOn = function(name, listener, scope){
                var unsubscribe = $delegate.$on(name, listener);

                if (scope){
                    scope.$on('$destroy', unsubscribe);
                }
            };

            return $delegate;
        }]);
    }]);

With this in place we can subscribe to events emitted by the $rootScope and have them automatically deregistered when our local $scope is being destroyed.

We can use it like this:

angular
    .module('MyApp')
    .controller('MyController', ['$scope', '$rootScope', function MyController($scope, $rootScope) {

            $rootScope.$saveOn('someComponent.someCrazyEvent', function(){
                console.log('foo');
            }, $scope);
        }
    ]);

However, I think we could do much better by providing a $onRootScope method directly on the Scope type so that it's available on every $scope. This would then automatically make the deregistration for us but we wouldn't have to pass the $scope explicitly.

It would simply look like this.

angular
    .module('MyApp')
    .controller('MyController', ['$scope', function MyController($scope) {

            $scope.$onRootScope('someComponent.someCrazyEvent', function(){
                console.log('foo');
            });
        }
    ]);

As far as I know, I can't monkey patch that directly.

Shamelessly pulling @IgorMinar @mhevery @btford and @petebacondarwin and @matsko into this issue ;-)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions