AngularJS - 如何公开服务属性

AngularJS - How to expose service properties

我很难公开 Angular 服务的属性。在下面的示例中,我在 authService 中公开了两个属性:isAuthenticateduser。然而,当 isAuthenticated 发生变化时,它不会被 HomeController 拾取。有人可以帮助我了解我哪里出错了吗?

(function() {
    'use strict';

    // Define the 'app' module
    angular.module('app', []);

    // Use the 'app' module
    angular
        .module('app')
        .controller('LoginController', LoginController)
        .controller('HomeController', HomeController)
        .factory('authService', authService);


    // ----- LoginController -----
    LoginController.$inject = ['authService'];
    function LoginController(authService) {

        var vm = this;
        vm.username = null;
        vm.password = null;
        vm.login = login;

        function login() {
            authService.login(vm.username, vm.password);
        }
    }


    // ----- HomeController -----
    HomeController.$inject = ['$scope', 'authService'];
    function HomeController($scope, authService) {

        var vm = this;
        vm.user = null;

        $scope.$watch(
            function() { return authService.isAuthenticated; },
            function() {
                console.log('HomeController: isAuthenticated changed');
                vm.user = authService.user;
            }
        );
    }


    // ----- authService -----
    function authService() {

        var isAuthenticated = false;
        var user = { username: 'jdoe', location: 'Dreamland' };

        var service = {
            login: login,
            isAuthenticated: isAuthenticated,
            user: user
        };

        return service;

        function login(username, password) {

            user = {
                username: username,
                location: 'Boston'
            };

            isAuthenticated = true;
            console.log('authService: isAuthenticated changed');
        }
    }

})();

这是 index.html 文件:

<!DOCTYPE html>
<html data-ng-app="app" ng-strict-di>
<head>
    <meta charset="utf-8">
    <title>AngularJS Minimal Template</title>
    <link rel="stylesheet" href="app.css">
</head>

<body>
    <div ng-controller="LoginController as vm">
        <form name="loginForm" ng-submit="vm.login()">
            <label>Username: </label>
            <input type="text" name="username" ng-model="vm.username">

            <label>Password: </label>
            <input type="password" name="password" ng-model="vm.password">

            <button type="submit">Login</button>
        </form>
    </div>

    <div ng-controller="HomeController as vm">
        <h1>{{vm.user.username}}</h1>
        <h2>{{vm.user.location}}</h2>
    </div>

    <!-- JavaScript at the bottom for fast page loading -->
    <script src="lib/angular.js"></script>
    <script src="app.js"></script>
</body>
</html>

而不是这样做

var service = {
            login: login,
            isAuthenticated: isAuthenticated,
            user: user
        };

尝试这样做

var service = {
            login: login,
            isAuthenticated: function() { return isAuthenticated; },
            user: function() { return user; }
        };

那么您需要将其作为函数而不是值来调用。这将在您每次调用 service.isAuthenticated() 时检查 isAuthenticated 值和 return 它。你应该对 user 做同样的事情。你应该打电话给 service.user().

当你这样做时:

var service = {
    login: login,
    isAuthenticated: isAuthenticated,
    user: user
};

您正在创建 loginisAuthenticateduser 的副本(尽管 user 是对同一对象的引用)。

然后,当你这样做时:

function login(username, password) {

    user = {
        username: username,
        location: 'Boston'
    };

    isAuthenticated = true;
    console.log('authService: isAuthenticated changed');
}

您正在将 local user 变量重新分配给新对象,并将 local isAuthenticated 变量重新分配给true。您的 service 对象仍然引用这些变量的 old 值。

解决此问题的最直接方法是直接分配给您的服务变量:

function login(username, password) {

    service.user = {
        username: username,
        location: 'Boston'
    };

    service.isAuthenticated = true;
    console.log('authService: isAuthenticated changed');
}

这样,服务变量将被更新,并且应该反映在使用该服务的任何地方。在这种情况下,您不再需要局部变量——服务对象已经包含了它们。对私有的、未公开的变量使用局部变量。