2

我的这段代码大部分都在工作,但我很难看到更改从控制器中的用户对象传播。

我想要做的是建立一个单一的User服务来管理我网站上当前用户的所有方面。例如:User.login(), User.logout(), User.currentUser,User.isLoggedIn等。

请记住,我对 Angular 和 ngResource 还比较陌生 :-)。

  • 有没有更好/更 Angular 的方式来构建它?
  • $resource 工厂上的自定义属性甚至可能吗?
  • 感觉好像我$rootScope.$apply()在这里需要一个或类似的?

    /**
     * The $resource factory.
     */
    angular.module('myApp.services', ['ngResource'])
      .factory('User', ['$resource', '$http', function($resource, $http) {
        var User,
            anonymousUser,
            currentUser,
            isLoggedIn;
    
        anonymousUser = { uid: 0, pass: null, name: 'Anonymous' };
        currentUser = angular.copy(anonymousUser);
        isLoggedIn = false;
    
        User = $resource('api/user/:verb', {}, {
    
          login: {
            method: 'POST',
            params:  { verb: 'login' },
            isArray: false,
            // (Ab)using the transformResponse callback to update currentUser
            // and isLoggedIn when necessary.
            transformResponse: $http.defaults.transformResponse.concat([
              function (data, headersGetter) {
                if (angular.isObject(data) && angular.isObject(data.user)) {
                  currentUser = data.user;
                  isLoggedIn = true;
                }
                // TODO: Flipping to anonymous user when a login error occurs. Double check if this logic is sound.
                else {
                  currentUser = angular.copy(anonymousUser);
                  isLoggedIn = false;
                }
    
                return data;
              }
            ])
          },
    
          logout: {
            method: 'POST',
            params:  { verb: 'logout' },
            isArray: false, // eg: [true] transformed to { result: true }
            // (Ab)using the transformResponse callback to update currentUser
            // and isLoggedIn when necessary.
            transformResponse: $http.defaults.transformResponse.concat([
              function (data, headersGetter) {
                if (angular.isArray(data) && data.length > 0) {
                  if (data[0] === true) {
                    currentUser = angular.copy(anonymousUser);
                    isLoggedIn = false;
                  }
    
                  return { result: data[0] };
                } else {
                  // TODO: Deal with indeterminate state here. Is the user logged in still or not?
                  // TODO: Return error.
                  return { result: false };
                }
              }
            ])
          }
        });
    
        // FIXME: Adding extra properties onto our $resource here. These ARE visible in the controller but bindings and $watch don't work on them.
        User.isLoggedIn = isLoggedIn;
        User.currentUser = currentUser;
    
        // FIXME: Attempting to bring these objects under the purview of Angular but this isn't helping.
        $rootScope.isLoggedIn = isLoggedIn;
        $rootScope.currentUser = currentUser;
    
        return User;
      }]);
    
    
    /**
     * The controller.
     */
    angular.module('myApp.page', [])
      .controller('NavbarCtrl', ['$scope', 'User', function ($scope, User) {
        // These work, but are not dynamically updated when User.login() and User.logout() are called.
        $scope.currentUser = User.currentUser;
        $scope.isLoggedIn = User.isLoggedIn;
    
        // FIXME: $watch is only called once, changes in User.login() and User.logout() do not invoke $watch here.
        $scope.$watch('currentUser', function (newVal, oldVal) {
          console.log([newVal, oldVal], 'Watching curentUser');
        }, true);
      }])
    
4

3 回答 3

1

这不是角度方式。如果您想创建服务 - 创建服务,角度有为此提供工具,您可以在此处阅读有关此的信息。工厂不应该有逻辑。因此,在您的服务方法中创建登录、注销等,并借助 $http 向您的服务器发送请求。

于 2013-07-05T13:43:01.647 回答
0

有没有更好/更 Angular 的方式来构建它?

这完全是意见。我认为,如果您创建它以使组件具有可读性和可重用性,那么这就是“角度”方式。我有类似的设置,但我将“isLoggedIn”分离到一个单独的工厂。(我将在下面说明这一点)。

$resource 工厂上的自定义属性甚至可能吗?

不明白你的意思。但是,如果您的意思是创建自己的方法,例如 $login(),那么答案是肯定的。

感觉好像我在这里需要一个 $rootScope.$apply() 或类似的东西?

您可以使用回调设置 $scope 变量。我的方法使用 $resource 对象的实例,因此它可能与您的方法有些不同:

将用户分成不同的服务:

.factory('UserSession', function(){
    var user = {
        "name": '',
        "isLoggedIn": false
    };

    return user
});

只是我的意见简化 $resource 工厂:

.factory('User', ['$resource', '$http', function($resource, $http) {
    return $resource('api/user/:verb', {}, {

        login: {
          method: 'POST',
          params:  { verb: 'login' },
          isArray: false

        },
        logout: {//}

    });
}]);

在控制器中,注入“用户”和“用户会话”,并为 $resource 实例添加回调:

.controller('whatever', ['$scope', 'User', 'UserSession', function($scope, user, sess){
    var logged = sess.isLoggedIn;
    if (!logged){
        var u = new user();
        u.$login({},function(data){ // I forgot the "$" originally - oops.
            $scope.currentUser = data.user.name; // whatever the object looks like;
            sess.isLoggedIn = true;
            sess.name = data.user.name; 
            // now UserSession can be used in other parts of the app
            // may need $scope.$broadcast if other controllers are currently using this data
        }
    }
}])  

同样,这只是意见。:)

于 2013-07-05T14:29:02.493 回答
0

也许您可以尝试为此使用原型。但我仍然不知道这是一种真正的角度方式

.factory('User', ['$resource', ($resource) ->
  user = $resource API_PATH + "/user", {},
    update: {method: 'PUT'}
  user.prototype.login = ->
    blah_blah()

  user.prototype.logout = ->
    blah_blah()

  user

然后像这样使用它:

user = new User() user.login();

于 2013-07-05T13:51:33.330 回答