2

複数のコントローラーとビューで使用される集中型データ ストレージとして機能する「アカウント」サービスがあります。このサービスは、getter メソッドと setter メソッドのほかに、ログイン ユーザーと匿名ユーザーという 2 種類のユーザーに関連付けられたすべてのデータを保持します。

このサービスの背後にある考え方は、関連するすべてのビューとコントローラーの同期を維持する集中型データ構造として使用する必要があるというものです。例: ユーザーがログインすると、自分の電子メールがわかり、すべての「ニュースレター購読」フィールドに事前入力できます。

私が使用している現在のセットアップは以下のとおりです。サーバー上の各 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().property を介してデータをビューにバインドするたびに、アプリ全体で同期が維持されます。

上記のコードは、たとえば .UserName 値が定義されていない場合、または匿名ユーザーの場合にアカウント データがまったくない場合にもスローされます。これを回避する 1 つの方法は、サービス内の「テンプレート」オブジェクトを null 値で「ダンプ」することです。これにより、キー/値が存在することが保証されます。もう 1 つの方法は、ウォッチャーを使用して、ユーザーがフィールドに入力した場合にコントローラーがサービスに「書き込む」ようにすることです。

最初のオプションでは、サービス内のすべてのデータ バインディングを一元化できるため、柔軟性が高くなりますが、サーバー データがどうなるかわからないため、たとえば別の形式で入ってくる可能性があるため、面倒です。

誰にも他の解決策がありますか?コントローラーにサービスへのデータの書き込みをさせたくないのです。

お時間をいただきありがとうございます!

4

2 に答える 2

2

ここにはたくさんの質問がありますが、できる限りお答えします。

いいえ、あなたがしていることは「ベストプラクティス」ではありません。

まず、モデルをビューに直接注入する必要があります。値を維持することは、「$scope」の助けを借りてコントローラーの責任です。Your "ng-model="Controller.getUserData().UserName" is bad. 以下に気づいたブログ記事の最後に、何をすべきかの良い例があります。

次に、サービスからデータをフェッチする場合、ほとんどの場合、応答は非同期になるため、Promise API を調べた方がよいでしょう。AngularJS の公式ドキュメントは常に素晴らしいとは限りません。Google グループやブログ記事で答えが見つかることもあります。

あなたの問題については、ここに良い記事があります: http://markdalgleish.com/2013/06/using-promises-in-angularjs-views/

于 2013-08-19T11:41:40.200 に答える
2
  1. まず、AngularJS でサービスを使用する場合、サーバーまたはデータをすぐに返さない可能性があるものへの呼び出しが必要です。したがって、醜いコールバックまたは美しいを使用する2つのアプローチがあります$q

promise の方が書きやすいので、私は promise を使用することを好みます。あなたのスニペットをより良い方法で書き直します:

// 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"/>
于 2013-08-19T11:44:44.567 に答える