简体   繁体   中英

AngularJS: Bind angular service property to scope

Scenario

  • I have a service UserService that maintains the (boolean) sessionStatus of the user.
  • The view conditionally shows [LOGOUT] on ng-show=sessionStatus (ie 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();
        })
      }
    };
  });

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM