angularjsangularjs-rootscopeangularjs-1.6

Best practice for using $rootscope in an Angularjs application?


We have a large Angularjs 1.6 application that has $rootscope scattered throughout the app in over 200 places in filters, services, routes, etc.. so it needs to be refactored, but I'm not sure how to know when to remove it. When is it a best practice to use $rootscope in the application?

I've read everything from never, to using it for storing variables, which I assumed was for sharing data between controllers. I've since read that it's better to use factories/services for this use case instead and I also read that one valid use case is to use $rootscope as a global event bus.

I didn't really see this explained in the Angularjs docs.


Solution

  • From ng-book:

    When Angular starts to run and generate the view, it will create a binding from the root ng-app element to the $rootScope. This $rootScope is the eventual parent of all $scope objects. The $rootScope object is the closest object we have to the global context in an Angular app. It’s a bad idea to attach too much logic to this global context, in the same way that it’s not a good idea to dirty the JavaScript global scope.

    You are right, you should definitely use Services to share data and logic between your modules.

    Putting a lot of logic in your $rootScope means having bad maintainability and modularity in your application, it is also very difficult to test issues.

    I highly suggest you to take a look at:

    I know it may be easy to attach everything to $rootScope, but It is just difficult to work on it, make little changes, reusing your code for other applications or modules and test your application in general.

    EDIT

    Recently I had to fetch some items from API and catch these items in order to show them in a certain view. The item fetching mechanism was in a certain Factory, while the mechanism to format and show the items was in a Controller.

    So, I had to emit an event in the Factory when items got fetched and catch this event in the Controller.

    $rootScope way

    //Factory
    $rootScope.$broadcast('refreshItems', items);
    //Controller
    $scope.$on('refreshItems', doSomething());
    

    It clearly worked but I didn't really like to use $rootScope and I've also noticed that the performance of that task were pretty miserable.

    Then I tried giving a shot to Postal.js:

    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 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 emitting/aggregation.

    I tried using Postal.js for this kind of needs and I found out that it is really faster than using $rootScope for this purpose.

    //Factory
    $scope.$bus.publish({
                      channel : 'reloadItems',
                      topic   : 'reloadItems'
                      data    : items
    );
    
    //Controller
    $scope.$bus.subscribe({
      channel  : 'reloadItems',
      topic    : 'reloadItems',
      callback : function () {
        resetAndLoadItems();
      }
    });
    

    I hope I've been helpful.