AngularJS。关于从服务进行正确的双向数据绑定的最佳实践

时间:2013-08-19 11:30:23

标签: javascript angularjs angularjs-service

我有一个'帐户'服务,充当多个控制器和视图中使用的集中数据存储。除了getter和setter方法之外,该服务还将保存与两类用户相关的所有数据,即登录用户和匿名用户。

这项服务背后的理念是它应该被用作一个集中的数据结构,它将使所有相关的视图和控制器保持同步。例如:如果用户登录,他们将知道他的电子邮件,并且所有“简报订阅”字段都可以预先填写。

我使用的当前设置如下。请注意,服务器上的每个Async调用都将返回一个promise。

// The Service
angular.module('A').provider('AccountService', [function() {

    this.$get = function ($resource) {

        var Account = {
            getLoggedInAccountAsync : function () {
              var Account = $resource(WebApi.Config.apiUrl + 'Account/Get');
              return Account.get();
            },

            getUserData : function () {
                return Account.userData; 
            },

            setUserData : function (accountData) {
                var merge = angular.extend((Account.currentAccountData || {}), accountData);
                Account.currentAccountData = merge; 
            }    
        };

        return Account;
    }
});

// Our main app controller. Get's fired on every page load.
angular.module('A').controller('MainController', ['AccountService', function (AccountService) {

    var loggedInAccount = AccountService.getLoggedInAccountAsync();
    loggedInAccount.$then(loggedInAccountPromiseResolved);

    function loggedInAccountPromiseResolved (response) {
       if (response.data.isLoggedIn) {
           AccountService.setAccountData(response.data);
       }
    };

    return $scope.MainController= this;
}])

// Our specific controller. For example a newsletter subscription.
angular.module('A').controller('SpecificController', ['AccountService', function (AccountService) {
    this.getUserData = AccountService.getUserData;
    return $scope.Controller = this;
}])

// Newsletter subscription view
<input id="email" type="email" name="email" ng-model="SpecificController.getUserData().UserName"/>

使用上面的代码确保每当我们使用服务通过Controller.getUserData()。属性将我们的数据绑定到我们的视图时,它将在整个应用程序中保持同步。

如果未定义.UserName值,或者如果没有用户,则上面的代码也将抛出。或者根本没有帐户数据。解决此问题的一种方法是使用空值在我们的服务中“转储”我们的“模板”对象,这将确保键/值存在。另一种方法是使用观察者,让我们的控制器“写”到我们的服务,以防用户填写字段。

第一个选项为我提供了更多的灵活性,因为我可以集中服务中的所有数据绑定,但它感觉很脏,因为你永远不知道服务器数据会发生什么,例如它可能以不同的格式出现。

有没有人有其他解决方案?我宁愿不让我的控制器将数据写入服务。

感谢您的时间!

2 个答案:

答案 0 :(得分:2)

这里有很多问题,我会尽我所能回答。

不,你在做什么不是“最佳做法”。

首先,应该将模型直接注入到视图中,并且在“$ scope”的帮助下,维护值是Controller的责任。你的“ng-model =”Controller.getUserData()。UserName“很糟糕。在我下面注意到的博客文章的最后有一个很好的例子。

其次,当你从服务中获取数据时,大部分时间,答案都是异步的,所以你最好看看Promise API。 AngularJS的官方文档并不总是很棒,有时可以在谷歌小组或博客文章中找到答案。

对于您的问题,这是一篇很好的文章:http://markdalgleish.com/2013/06/using-promises-in-angularjs-views/

答案 1 :(得分:2)

  1. 首先,如果您在AngularJS中使用服务,我们希望调用服务器或任何可能无法立即返回数据的服务。所以我们有两种方法可以使用丑陋的回调或漂亮的$q
  2. 我更喜欢使用承诺,因为它更清晰。我会以更好的方式重写你的片段:

    // Service
    angular.module('A').provider('AccountService', [function() {
    
        this.$get = function ($resource, $q) {
    
            var Account = {
                getUserData : function () {
                    var d = $q.defer();
                    d.resolve(Account.userData);
                    return d.promise; 
                }    
            };
    
            return Account;
        }
    });
    
    // Controller
    angular.module('A').controller('Controller', ['AccountService', function (AccountService) {
        var init = function() {
          getUserData();
        };
    
        var getUserData = function() {
           AccountService.getUserData().then(function(data) { $scope.username = data; }); 
        };
    
        init();
        //return $scope.Controller = this; // you don't need to do this 
    }])
    

    HTML:

    <input id="email" type="email" name="email" ng-model="username"/>