Chrillewoodz
Chrillewoodz

Reputation: 28338

Can't access authData bound to $rootScope from one of the controllers

I've got a bug which is driving me nuts, basically all I'm trying to do is to set a $rootScope.authData property which holds a user's authentication information so that I can use it in different controllers.

However, when I try this it's just gives me an error saying $rootScope.authData is not defined. I've checked and it is indeed defined when logging it to the console from the mainCtrl, but it's undefined when logging it to the console from the tagsCtrl.

This is strange considering the fact that I can use the $rootScope.authData in one of my other controllers.. And also I if I add $rootScope.test = 'testing' in the mainCtrl and console log that in the tagsCtrl it works.

I can't see anything wrong that I've done here and I've reached a dead end. Any ideas?

Main controller which sets the $rootScope.authData:

flickrApp.controller('mainCtrl', ['$scope', '$rootScope', '$firebase', 'Auth', function($scope, $rootScope, $firebase, Auth) {

    Auth.$onAuth(function(authData) {
        $rootScope.authData = authData;
        console.log($rootScope.authData); //Is defined here
    });
}]);

The controller that can't access the $rootScope.authData:

flickrApp.controller('tagsCtrl', ['$scope', '$rootScope', '$firebase', function($scope, $rootScope, $firebase) {

console.log($rootScope.authData); //Is not defined here

}]);

EDIT: After some feedback from Bricktop I tried to create a service for this, which turned out like this:

flickrApp.service('shared', ['$scope', 'Auth', function($scope, Auth) {

    //Auth is a wrapper that points to my firebase reference

    Auth.$onAuth(function(authData) {
        return $scope.authData = authData;
    });
}]);

I'm not sure if this would be a valid one but it appears that it's not since I get this error:

Error: [$injector:unpr] http://errors.angularjs.org/1.3.10/$injector/unpr?p0=%24scopeProvider%20%3C-%20%24scope%20%3C-%20shared
at Error (native)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js:6:417
at https://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js:38:307
at Object.d [as get] (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js:36:308)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js:38:381
at d (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js:36:308)
at e (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js:37:64)
at Object.instantiate (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js:37:213)
at Object.<anonymous> (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js:37:490)
at Object.e [as invoke] (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js:37:96)

I inject it like this:

flickrApp.controller('tagsCtrl', ['$scope', '$firebase', 'shared', function($scope, $firebase, shared) {

    console.log($scope.authData.uid); //This would come from the 'shared' service now
}]);

What's wrong here?

Upvotes: 1

Views: 767

Answers (2)

Bricktop
Bricktop

Reputation: 1549

The above answer explains why it (probably) isn't working but I would recommend that you solve your problem (sharing variables between controllers) in a different manner.

You should instead create a service (something like "shared" ) and share data that way. This works because services are singletons while controllers are not. Additionally you don't add variables to your rootscope that will be carried around even if you don't need them.

To see a good example of such a shared service check here.

Here is my example that should work for your example:

Firstly the shared service:

flickrApp.service('shared', function() {

    var authentication = 'none';

    return {
        getAuth: function () {
                return authentication;
        },
        setAuth: function (auth) {
            authentication = auth;
        }
    };
});

I like to keep this shared service clean from all logic and use it only for sharing data.

Next up is the main controller you have to make sure that this is actually called before any other controller is called after login ( So you would put it in a controller that handles logging in !)

flickrApp.controller('mainCtrl', ['$scope', '$firebase', 'shared', 'Auth', function($scope, $firebase, Auth, shared) {

    Auth.$onAuth(function(authData) {
        shared.setAuth(authData);
        console.log(shared.getAuth()); //Check if it was set correctly
    });
}]);

Lastly any other controller that needs to check the logged in state :

flickrApp.controller('tagsCtrl', ['$scope', '$firebase', 'shared', function($scope, $firebase, shared) {
    $scope.auth = shared.getAuth();
    if($scope.auth === 'none'){
      console.log('you are not logged in!');
    }else{
        console.log('welcome '+$scope.auth.uid);
        //anything you would do if a user is logged in
    }
}]);

I assume that you know the following but I am just going to repeat this (I am not familiar with firebase) :

Always be aware that javascript code could be manipulated from a malicous user, make sure you send a user token with every http request you send to your server to make sure that the user is actually logged in and don't rely on javascript to do this for you.

If you have any other problems, please let me know.

Upvotes: 1

Yogesh Manware
Yogesh Manware

Reputation: 1843

here is a simple example of sharing data through shared service and scope

js

(function(app) {

    function SharedService() {
        this.user = {};
    }

    function Controller1(scope, SharedService) {
        scope.sharedService = SharedService;
    }

    function Controller2(scope, SharedService) {
        scope.sharedService = SharedService;
    }

    app.service('SharedService', SharedService);
    app.controller('Controller1', Controller1);
    app.controller('Controller2', Controller2);

})(angular.module('myApp', []));

html

<script src="https://code.angularjs.org/1.3.4/angular.js"></script>
<script type="text/javascript" src="js/exp2/app.js"></script>
<div ng-app="myApp">
    <div ng-controller="Controller1 as ctrl">
        </br> 
        <table>
            <tr>
                <td><B> Enter Age in Controller1</B></td>
                <td><input type="text" ng-model="ctrl.userAge"></select></td>
            </tr>
        </table>
    </div>
    <div ng-controller="Controller2 as ctrl">
        <table>
            <tr>
                <td><B> Age in controller2 : </B></td>
                <td>{{ctrl.userAge}}</td>
            </tr>
        </table>
    </div>
</div>

refer following link to know how to share data without using any sort of scope. http://plnkr.co/edit/den1mfMeIAWezLTuVZVX?p=preview

Upvotes: 0

Related Questions