DeLac
DeLac

Reputation: 1122

AngularJS : difference between $rootScope.Controller and Service

I am trying to understand Angularjs behaviors. I am building a web-app, and I want the CurrentUser's info be shared among all the app components. To do that, I have created a CurrentUserController bound to $rootScope. This controller is used by a user directive utilized in the body html element, so that it is globally accessible and it's created just one time.

app.controller('CurrentUserController', function ($rootScope) 
  {
   // initialization
   $rootScope.userCtrl = self; //<- MAKE IT GLOBAL
   this.islogged=false;
   this.name="";
   var self = this;
   // functions
   this.isLogged = function() 
        { return self.islogged; };

   this.setLoggedIn = function(credentials) 
        { self.islogged = true; }; 

   this.setLoggedOut = function() 
        { self.islogged = false; };                 
  }
);

app.directive('currentUser', function() {
  return {
    controller:'CurrentUserController'
  };
 })

and then my html page

<html>
...
<body current-user> 
...
</body>
</html>

However I read that Services should be used to share data between controllers, since they are singleton. So my question is: is my approach wrong, or it is equivalent as I utilized services?

Moreover, right now I can utilize the directive ng-switch calling $rootScope.userCtrl functions, like this:

<div id="nav-right-side" class="navbar-right" ng-switch on="userCtrl.isLogged()">
            <div ng-switch-when="false">
                <login-button></login-button>
            </div>
        <div ng-switch-when="true">
                <loggedin-button></loggedin-button>
            </div>                      

        </div>

If I utilize services, would I still be able to do that? Thank you

Upvotes: 1

Views: 1109

Answers (2)

Nicolas Joseph
Nicolas Joseph

Reputation: 1724

The $rootScope is indeed shared across all the app and it is also best to store models into services.

Why bother with services ? Because of the $digest cycle. Each time a watched value is modified, the digest is triggered. In angular, by default the digest is a loop that goes down all your scope from the $rootScope down to its leafs. On each element, it has to get if the value has been modified or not to update the view accordingly. This is pretty expensive, and it is the cause of why angular can be slow on big applications. Keeping the scope as light as possible is how you can build complex apps in angular. That's why storing things is always better in services, you do not pollute the scope with data you could put somewhere else.

That being said, auth is peculiar because you want to access the same data from the view and services. You can store it in the $rootScope as Asta puts it but I do not think that is consistant with best practices. This is opinionated

What can be done is creating a service that will hold you model and share it through a controller to have access to it from both the view and the other services/models.

Session.js

function Session(){
     var 
       self = this,

       _islogged=false,
       _name = '';
    // functions
    this.isLogged = function() { 
        return self.islogged; 
    };

    this.setLoggedIn = function() { 
         self.islogged = true; 
    }; 

    this.setLoggedOut = function() { 
        self.islogged = false; };                 
    }

    // GetUsername, setUsername ... Whatever you need
}
angular
    .module('app')
    .service('Session', Session);

rootController.js

function rootController(Session){
    // share the Session Service with the $scope
    // this.session is like $scope.session when using the controllerAS syntax.
    this.session = Session;
}

angular
    .module('app')
    .controller('rootController', rootController);

I would suggest you take a look at these articles:

Upvotes: 3

Asta
Asta

Reputation: 1579

Your best to use a Service to share data as you mention. In your approach you've used a Controller in a way that its not really intended.

You can call your controller from your HTML by using ng-controller so something like the following should work. This would be useful for a Login view for example or a logout directive.

<div ng-controller="userCtrl">
    <div id="nav-right-side" class="navbar-right" ng-switch on="isLogged()">
       <div ng-switch-when="false">
           <login-button></login-button>
       </div>
       <div ng-switch-when="true">
           <loggedin-button></loggedin-button>
       </div>                      
    </div>
</div>

In order to have your session available globally for use elsewhere you can use a service which you can initialise from your app. The session data can be added to $rootScope which you can then reference from any view or controller.

Service

angular.module('app').service('session', function($rootScope) {
    $rootScope.sessionData.loggedIn = true
    // extra logic etc..
});

Main App

angular.run(session)
angular.module('app').run(function(session) {});

Then to reference the variable from your view

<div id="nav-right-side" class="navbar-right" ng-switch on="sessionData.isLoggedIn">

Note: its good practice to use an object with scope variables to help avoid issues with inheritance.

Upvotes: 0

Related Questions