1

I'm trying to make a function that only shows a certain part of the html to users that have the right role. These are my functions:

nodejs/server.js

app.get('/api/isadmin', ensureAuthenticated, function (req, res) {
  User.findById(req.user, function (err, user) {

    res.send(user);
  });
});

This is where the problem occurs, it will run indefintely:

<ul ng-if="isAdmin()">
   <li>
       <a ui-sref="admin">Admin</a>
   </li>
</ul>

Why is this happening? I've looked at Satellizer's isAuthenticated function and basically done the same thing.

EDIT: Updated code:

adminservice.js

angular.module('App')
 .factory('AdminService', function ($q, $http, toastr) {

  return {
      getAdmin: function () {
          var httpget = $http.get('http://localhost:3000/api/isadmin');

          httpget.then(function (response) {
                var res = response.data.role;
                if (res == 'admin') {
                    console.log('true');
                    return true;
                }
                else {
                    console.log('false');
                    return false;
                }
            }, function (result) {
                return $q.reject(result);
            });

          return httpget;

      }
  };
});

navbar.js

angular.module('App')
 .controller('NavbarCtrl', function($q, $scope, $auth, AdminService) {

  $scope.isAuthenticated = function() {
     return $auth.isAuthenticated();
  };

  AdminService.getAdmin().then(
    function (result) {
        $scope.isAdmin = result;
    });
});

both responses, true or false, can still see the Admin list element.

Kuja
  • 449
  • 6
  • 20
  • Take a look at this: http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call – dfsq May 14 '16 at 21:11
  • `adminService.getAdmin()` doesn't return anything. Also a terrible approach to place a function in the view that will constantly make `$http` requests. Need to understand how digest cycles work and see how many times that gets called ... it;s far more than you think. Set a scope variable inside promise callback instead – charlietfl May 14 '16 at 21:16
  • @charlietfl I do see that my current approach is not good, but I've struggled to get it working all-together. What do you mean by setting a scope variable inside a promise check? – Kuja May 14 '16 at 21:27
  • 1
    return `$http` from `adminService.getAdmin()` and in controller do something like `AdminService.getAdmin().then(function(result){ $scope.isAdmin = result; })`. then use that variable (not function) in `ng-if` – charlietfl May 14 '16 at 21:29
  • @charlietfl by 'use that variable' you mean the $scope.isAdmin? just by doing ng-if="isAdmin" ? – Kuja May 14 '16 at 21:40
  • yes ... always use asynchronous calls to assign scope property variables – charlietfl May 14 '16 at 21:49
  • @charlietfl Could you check my updated code? I think I did what you suggested, but even if it responds true or false, they can still see the button Admin. – Kuja May 14 '16 at 22:17
  • so use dev tools console to see what `response.data.role` is and what is returned to controller. Also should probably change `return $q.reject(result);` to `return false` and also update html to `ng-if="isAdmin"` – charlietfl May 14 '16 at 22:25
  • You aren't using the deferred correctly. You should be returning the `deferred.promise` and then in your callbacks used use `.resolve(response)`. Check out the examples [here](https://docs.angularjs.org/api/ng/service/$q) – Clint May 14 '16 at 22:25
  • @Clint that is an anti pattern when `$http` itself already returns a promise – charlietfl May 14 '16 at 22:28

1 Answers1

1

I was about to write a lot of things. Since you figured out and updated your code, let me fix the existing problems. You need to return the promise instance from getAdmin function, not httpget.

angular.module('App')
 .factory('AdminService', function ($q, $http, toastr) {

  return {
      getAdmin: function () {
          var httpget = $http.get('http://localhost:3000/api/isadmin');

          return httpget.then(function (response) {
                var res = response.data.role;
                if (res == 'admin') {
                    console.log('true');
                    return true;
                }
                else {
                    console.log('false');
                    return false;
                }
            }, function (result) {
                // just return false
                return false;
            });
      }
  };
});

Your controller looks fine. In the html part, tie ng-if with isAdmin property.

<ul ng-if="isAdmin">
   <li>
       <a ui-sref="admin">Admin</a>
   </li>
</ul>

Hope, this helps.

Update

Only returning httpget will return promise instance, but you will get the actual response in the resolve function. The response that you get calling http://localhost:3000/api/isadmin. See this plunk: http://plnkr.co/edit/9UtYJlm9BalTi8HHTrV2?p=preview

Saad
  • 942
  • 6
  • 15
  • I edited my promise in the adminservice with your method, and it seems to work, only one problem. it checks it once, and only once. So if you arent logged in, it wont check again even if you log in and are admin. But if I log in, open a new browser window the button will be there. – Kuja May 14 '16 at 23:04
  • @KTown Why you want to check `isAdmin` again and again? Your controller loads when you go to that route/state or where you defined ng-controller. If you open another browser window and go to that route/state, the controller will load again and check `isAdmin`. – Saad May 14 '16 at 23:35
  • I figured that out yea. The reason is that I want the navbar to update if the user is admin or not, and then add the button or not based on that information. Satellizer's isAuthenticated() works that way, and I'm hiding and showing
      's based on if its true or not, which is basically what I'm looking to do with this.
    – Kuja May 14 '16 at 23:43
  • So, you are basically trying to create a method like `isAuthenticated`? – Saad May 15 '16 at 00:05
  • basically yea, but to check if the person is admin or not. – Kuja May 15 '16 at 00:11
  • Glad to hear that! But unfortunately, Satellizer's auth implemention is out of this post's context. I just saw Satellizer's code. They used localStorage. When a user logs in, he calls server side and then stores auth token information in client side localStorage. The `isAuthenticated` function checks if the token is there in localStorage and whether it expired or not. That't it. – Saad May 15 '16 at 00:25
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/111952/discussion-between-k-town-and-saad). – Kuja May 15 '16 at 00:26