0

I am using the angular ng-show directive to check if a user is an admin user and if they are then I want certain html elements to be "shown".

I firstly created the following function called checkIfUserIsAdmin in my mainController:

 $scope.checkIfUserIsAdmin = function(){
        var userPrivilegeID = sharedFactory.userDetails.userPrivilegeID; 
        if(userPrivilegeID === 2){
            return true;
        }else{
            return false;
        }
    }

and in my html I had the following:

<span ng-show="checkIfUserIsAdmin()"><i class="fa fa-check-circle"></i></span>

It was working well with ng-show and the html was changing as planned when the userPrivilegeID changed value.

However I decided I want to define this function in a factory instead so that I can pass it to multiple controllers.

However now when the userPrivilegeID changes the view does not update (as it should with ng-show). Apologies if it's a silly mistake but i've been trying to figure it out a while now and haven't found anything online. Can you help please?

sharedFactory.js

//create a factory so that we can pass these variables between different controllers. 
myApp.factory('sharedFactory', function(){
    //private variables
    var userDetails = {   
        "userID" : null,
        "userPrivilegeID" : 1,
        "isLoggedIn" : false
    }; 
    var checkIfUserIsAdmin = function(){
        var userPrivilegeID = userDetails.userPrivilegeID; 
        if(userPrivilegeID === 2){
            return true;
        }else{
            return false;
        }
    };

    //return public API so that we can access it in all controllers
    return{
        userDetails: userDetails,
        checkIfUserIsAdmin: checkIfUserIsAdmin
    };
});

mainController.js

 myApp.controller("mainController", function($scope, sharedFactory){
        $scope.checkIfUserIsAdmin = function(){
            return sharedFactory.checkIfUserIsAdmin; 
        }  
    });

index.html file (the most relevant parts for this question)

 <body data-ng-controller="mainController">
        <div id="container_wrapper">
            <div class="container"> 
                <span ng-show="checkIfUserIsAdmin()"><i class="fa fa-check-circle"></i></span>
                <div ng-view>
                    <!--our individual views will be displayed here-->
                </div>
            </div>
        </div>
    </body>

Edit: The userPrivilegeID is initialized to 1 as you can see above. However after I do an API call It is then set to 2 however ng-show is not updating to display the html. Here is my loginFactory which contains the API call

myApp.factory('loginFactory', function($http, $timeout, $q, sharedFactory){

    //Methods which perform API calls 
    var checkLoginDetails = function(data){
        var deferred = $q.defer();
        $http({
            method: 'POST',
            url: 'http://localhost/API/auth?apiKey=0417883d',
            data : JSON.stringify(data),
            headers: {
               'Content-Type': 'application/json;charset=utf-8'
            },
            responseType:'json'
        }).then(function successCallback(response){

            if(response.hasOwnProperty('data') && response.data !== null){
                console.log(JSON.stringify(response.data));
                sharedFactory.userDetails = {
                   "userID" : response.data.userID,
                   "userPrivilegeID" : response.data.userPrivilegeID, 
                   "isLoggedIn" : true
                };

                $timeout(function() {
                    deferred.resolve(sharedFactory.userDetails);
                }, 100);
            }else{
                sharedFactory.buildErrorNotification(response);

            }
        },function errorCallback(response){
            sharedFactory.buildErrorNotification(response);

        });
        //return the userDetails promise
        return deferred.promise;
    };


    //return public API so that we can access it in all controllers
    return{
        checkLoginDetails: checkLoginDetails
    };
});

And then in my mainController I have the following (which calls the checkLoginDetails function):

$scope.loginWithFacebook = function(){

    var data = {//...
    };

    loginFactory.checkLoginDetails(data).then(function(userDetails) {
        //Since the checkLoginDetails method (in the loginFactory) is performing a http request we need to use a promise
        //to store the userDetails (from the response) into our $scope.userDetails variable. 
        $scope.userDetails = userDetails;
    });

}  
Sarah
  • 1,943
  • 2
  • 24
  • 39
  • 1
    It appears that you're not really calling the factory function, just returning the factory function. You need to add the parenthesis to the `checkIfUserIsAdmin` call in your controller. – Baldy Oct 04 '17 at 22:01
  • @Baldy oops. thanks. I did that now. But it still doesn't work as expected. A little more info: The userPrivilegeID is initialized as 1 as you can see. Then I do a http request to an API and when I get a response I update the userPrivilege to 2. However I expect the html to change with ng-show at this point but they don't. I'm using promises when I get a response from the http request. Could this be causing the problem?Thanks – Sarah Oct 04 '17 at 22:11
  • Can you share the code for the API call? – JC Ford Oct 04 '17 at 22:16
  • @JC Ford I just edited my question to include the code for the API call. – Sarah Oct 04 '17 at 22:32
  • I see it. Why the `$timeout`? – JC Ford Oct 04 '17 at 22:33
  • This doesn't relate to your problem, but you do not need the `$timeout` or the `$q.defer()`. The `$http` service creates a promise. You can just return it. – JC Ford Oct 04 '17 at 22:40
  • @JC Ford Thanks but I was initially doing it without a promise and the scope variable didnt update properly so I found the solution on stackoverflow. I had my checkLoginDetails() function returning the userDetails and I had this in my controller before: $scope.userDetails = loginFactory.checkLoginDetails(data); but it didnt work properly. I found people with the same problem. – Sarah Oct 04 '17 at 22:48
  • @JC Ford. I just wanted to say thanks for the hint about not needing the $q or $timeout. I have since read this article and got it working without promises like you said: http://www.codelord.net/2015/09/24/%24q-dot-defer-youre-doing-it-wrong/ But what I was missing (in order to get it working without $q and $timeout) was having "return" in front of the $http request as follows: `return $http.get('options.json').then(function(response) { return response.data; });` – Sarah Oct 10 '17 at 18:15

1 Answers1

1

You left off the parens on the call to your service function.

 myApp.controller("mainController", function($scope, sharedFactory){
        $scope.checkIfUserIsAdmin = function(){
            return sharedFactory.checkIfUserIsAdmin(); //<-- Needs to actually call the function.
        }  
    });

Change your service to something like this:

//create a factory so that we can pass these variables between different controllers. 
myApp.factory('sharedFactory', function(){
    //private variables

    var service = {
        userDetails: {   
            "userID" : null,
            "userPrivilegeID" : 1,
            "isLoggedIn" : false
        }
    };

    service.checkIfUserIsAdmin = function (){
        var userPrivilegeID = service.userDetails.userPrivilegeID; 
        if(userPrivilegeID === 2){
            return true;
        }else{
            return false;
        }
    };

    //return public API so that we can access it in all controllers
    return service;
});
JC Ford
  • 6,946
  • 3
  • 25
  • 34
  • thank you. Please see my comment above to "Baldy" as it still isn't working as expected. – Sarah Oct 04 '17 at 22:12
  • In your API promise handler, you're setting `sharedFactory.userDetails` but in your `sharedFactory` service, the `userDetails` is a local variable, not a property. That local variable is preserved in the closure for your `checkIfUserIsAdmin` function. The function never looks at the value stored as a property. – JC Ford Oct 04 '17 at 22:34
  • Oh yea i get you. the userDetails variable only becomes global when I return it from the sharedFactory at the end. – Sarah Oct 04 '17 at 22:39
  • although I have to return it like this otherwise causes error: return{service: service}; – Sarah Oct 04 '17 at 22:53