可以在$ resource工厂上添加自定义属性并将更改传播到这些属性吗?

时间:2013-07-05 13:19:14

标签: angularjs angular-resource

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

我要做的是构建一个User服务来管理我网站上当前用户的所有方面。例如:User.login()User.logout()User.currentUserUser.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);
      }])
    

3 个答案:

答案 0 :(得分:1)

这不是棱角分明的方式。如果你想创建服务 - 创建服务,角度有这方面的工具,你可以阅读关于此的信息here。工厂不应该有逻辑。因此,在您的服务方法中创建登录,注销等,并借助$ http发送请求到您的服务器。

答案 1 :(得分: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();

答案 2 :(得分:0)

  

是否有更好/更多的Angular方法来构建它?

这完全是意见。我认为如果你创建它以允许组件可读和可重用,那么这就是" angular"办法。我有类似的设置,但我将" isLoggedIn"进入一个单独的工厂。 (我将在下面说明这一点)。

  

$ resource工厂的自定义属性是否可能?

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

  

感觉好像我需要一个$ rootScope。$ apply()或者类似的吗?

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

将用户分成不同的服务:

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

    return user
});

JUST MY OPINION 简化了$ resource factory:

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

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

        },
        logout: {//}

    });
}]);

在控制器中,注入'用户'和' UserSession',并向$ 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
        }
    }
}])  

同样,这只是意见。 :)