2013-07-05 93 views
1

我有这个代码主要工作,但我很难看到更改从我的控制器中的用户对象传播。

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

请记住,我还是比较新的角度和ngResource :-)。

  • 有没有更好/更角度的方式来设计这个?
  • $资源工厂的自定义属性甚至可能吗?
  • 感觉我可能需要一个$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); 
        }]) 
    

回答

1

它没有棱角的方式。如果你想创建服务 - 创建服务,角度有这方面的工具,你可以阅读有关这方面的信息here。工厂不应该有逻辑。所以在你的服务方法中创建登录,注销等,并在$ http发送请求的帮助下向你的服务器发送请求。

+0

谢谢@dolgishev我会尝试这种方法。希望通过类似的对象避免许多不同,例如:User,UserResource等,但也许这是唯一的方法。 –

+0

你可以在你的服务中创建变量,这是一个资源,并添加方法来保存,查询等服务 – dolgishev

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();

+0

谢谢@SET。这似乎并不像Angular的方式,我同意。将服务而不是工厂采取dolgishev的方法。 –

0

是否有建筑师这更好/更角的方式?

这完全是意见。我认为,如果你创建这个允许组件是可读和可重用的,那么这就是“有角度”的方式。我有一个类似的设置,但我将“isLoggedIn”分隔为一个单独的工厂。 (我会在下面说明)。

甚至有可能在$资源工厂的自定义属性?

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

感觉就像我需要一个$ rootScope。$ apply()或类似的在这里?

你可以使用一个回调函数来设置$ scope变量。我的方法是使用$资源对象的实例,所以它可能会比你有点不同:

独立用户为不同的服务:

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

    return user 
}); 

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

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

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

     }, 
     logout: {//} 

    }); 
}]); 

和Controller,注入 '用户' 和 'UserSession',和一个回调添加到$资源实例:

.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 
     } 
    } 
}]) 

再次,这只是意见。 :)

+0

谢谢@rGil。是的,你所描述的方法是我最初实施的方式。从那时起,我一直试图将大部分逻辑和对象转化为服务,以减少代码重复。像'isLoggedIn'和'currentUser'这样的东西在整个应用程序中都是需要的,所以它们应该以某种方式成为全球性的。从我读过的所有服务是实现全球化的正确方法。工厂只是一种服务,请参阅:https://gist.github.com/Mithrandir0x/3639232 –