6

Scenario

  • I have a service UserService that maintains the (boolean) sessionStatus of the user.
  • The view conditionally shows [LOGOUT] on ng-show=sessionStatus (i.e. if not logged in (false), no show).
  • sessionStatus of ViewController should therefore always match that of UserService ... right?
  • If you click [LOGOUT] when it's visible, it does some loggy outty things, sessionStatus value changes, and view should update with new outcome of ng-show....

Problem

  1. Currently, clicking logout does not seem to update var UserService.sessionStatus?
  2. How do I keep $scope.sessionStatus updated when UserService.logout() occurs and changes UserService.sessionStatus?
    • How do I map the changing $scope to ng-show?

Files

View

    <a ng-show="sessionStatus" ng-click="logout()">Logout</a>

ViewController

    app.controller('AppController', function($scope, $interval, $http, UserService) {
      $scope.logout = function() { UserService.logout(); }

      // This ain't working
      $scope.$watch(UserService.sessionStatus, function() {
          $scope.sessionStatus = UserService.sessionStatus;
      });
    });

UserService

NB: appUser is an injected global var in the HTML head (a hacky fix until I get session/cookie stuff working properly)

  app.factory('UserService', function($http) {
    var pre;
    var sessionStatus;

    function init() {                   // Logged in  : Logged out             
      pre = appUser.user != undefined ? appUser.user  : { name: 'Logged out', uid: '0' };
      sessionStatus = pre.uid != "0"  ? true          : false;
    }

    function resetSession() { appUser = null; init(); }

    init();

    return {
      sessionStatus: function() { return sessionStatus; }, // update on change!

      logout: function() {
        $http.get("/logout").then(function (data, status, headers, config) {
          resetSession();
        })
      }
    };
  });
1
  • Just a suggestion, not asking you to change the requirements. But you should always keep showing the Logout link better don't hide and show. Still if you want to achieve that functionality then use $timeout and may be set timeout interval to 5 secs. In that timeout code call a service that will check if session is valid or not and update the scope variable accordingly. But for every 5 secs u wud be calling your server so keep that in mind. Commented Oct 13, 2014 at 16:00

2 Answers 2

9

Instead of a watch, simply use a scoped function that returns the session status from the service.

$scope.sessionStatus = function() {
    return userService.sessionStatus();
};

Your Logout link would look as below:

<a ng-show="sessionStatus()" ng-click="logout()">Logout</a>

A stripped down Plunker for your functionality: http://plnkr.co/edit/u9mjQvdsvuSYTKMEfUwR?p=preview

Sign up to request clarification or add additional context in comments.

3 Comments

Oh wow, a very elegant solution. Does Angular constantly run that function to check for changed values automatically or something?
Why is it that it doesn't work to just do $scope.sessionStatus = userService.sessionStatus;
How come the view won't refresh live if we change sessionStatus to : function(){return Date.now();} plnkr.co/edit/rW4Q7OMSzqVrk9fSBBsE?p=preview. I would expect seeing the milliseconds ticking.
2

Using a scoped function is cleaner and is the "correct" way to do it. Yet, for the sake of completeness you could also have fixed your watch:

$scope.$watch(function () {
    return UserService.sessionStatus;
}, function() {
    $scope.sessionStatus = UserService.sessionStatus;
});

The first argument of the $watch method takes a WatchExpression which can be a string or a method.

But again, $watch should not be used in controllers. Using scoped methods as suggested are cleaner and easier to test.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.