web-dev-qa-db-ja.com

AngularJSでCREATEコントローラーとEDITコントローラーを組み合わせるのは良い習慣ですか?

CREATEコントローラーとEDITコントローラーの間には重複したコードがたくさんあります。これらのコントローラーを1つに組み合わせて、繰り返しのコードを最小限に抑えることができます。

問題:フォームの送信に使用するメソッドを区別する必要があります-たとえば、create()またはedit()。

解決策:たとえば、$scope.modeを追加し、ユーザーが[編集]ボタンをクリックした場合は$scope.mode='edit'を設定し、ユーザーが[追加]ボタンをクリックした場合は$scope.mode='add'を設定できます。

繰り返しのコードを最小限に抑えるためのサービスを使用できますが、重複するコードは残ります。たとえば、両方のコントローラーに、フォームをクリアして非表示にするcancel()メソッドがあります。 clearForm()とhideForm()をサービスに格納できますが、このコードは両方のコントローラーで複製されます。

$scope.cancel = function() {
    Service.clearForm();
    Service.hideForm();
};

質問:

  • AngularJSでCREATEコントローラーとEDITコントローラーを組み合わせるのは良い習慣ですか?
  • 繰り返しのコードを最小限に抑えるための良い習慣はありますか?
22
webvitaly

はい。 1つのコントローラーを使用します。

これが1つのコントローラーを使用する理由です

コントローラの役割は、ビューをサポートすることです。作成ビューと編集ビューはまったく同じです。一方にはデータが事前入力されており(編集)、もう一方にはデータが入力されていない(作成)だけです。さらに、このビューの「目的」は、ユーザーにフォームに新しい値を変更または入力させることです。唯一の違いはreset()のようなものです。しかし、そこでさえ、空のモデルオブジェクトから始めることができます。 CREATEの場合は_$scope.entity = {}_で、$scope.entity = $http.get()から始めます。

2つのコントローラーでの繰り返しの問題

2つの異なるコントローラーとサービスを使用すると、少なくとも次の重複が発生します。

_$scope.cancel = function() {
    Service.cancel();
};

$scope.validate = function() {
   ValidtionSvc.validate();
}
.
.
.//other stuff similar
_

しかし問題は、あなたが述べたようなこの重複でさえなぜかということです。

(上記が最初の質問への回答だったので、ここ以降はUDATED)

1つのコントローラーを繰り返し使用する方法は?

繰り返しのコードを最小限に抑えるための良い習慣はありますか?

質問の再定義:CREATEフォームとEDITフォームで繰り返されるコードを削除する良い方法はありますか?

この特定の状況でコードが繰り返されるのを避けるための正式な「ベストプラクティス」は私の知る限り存在しません。ただし、mode = edit/createには反対することをお勧めします。この状況でのコントローラーの理由は、ユーザーが対話するときにモデルをフェッチ/更新することだけが仕事であるため、ほとんど違いがないはずです。

この状況で発生する違いと、mode = create/editを使用してif/then/elseを回避する方法は次のとおりです。

1)フォームに既存の値を入力するか、Createの空のフォームを入力します。

既存のエンティティをフェッチするには、いくつかのキー/クエリデータが必要です。そのような重要なデータが存在する場合、あなたはすることができます

_var masterEntity = {};
if(keyData) {
   masterEntity = MyEntityResourceFactory.getEntity(keyData);
} 
$scope.entity = masterEntity;//for Create this would be {}
_

2)reset()フォームは単純でなければなりません

_   $scope.reset = function() {
      $scope.entity = masterEntity;
   }
_

3)更新/作成

_$http.post()//should not be different in today's world since we are treating PUT as POST
_

4)検証-これは完全な再利用です-違いはないはずです。

5)初期/デフォルト値

{}の代わりにmasterEntity = Defaultsを使用できます。

31
bhantol

AngularJSでCREATEコントローラーとEDITコントローラーを組み合わせるのは良い習慣ですか?

私の経験では、そうです、99.9%の確率でそれは良い考えです。私は通常、formType変数を$ routeProvider解決機能を介してコントローラーに挿入します。だから私は次のようなものを持っているでしょう:

$routeProvider
    .when('/item/create', {
        templateUrl: '/app/item/itemForm.html',
        controller: 'itemFormController',
        resolve: {
            item: ['$route', 'itemRepository', function ($route, itemRepository) {
                return itemRepository.getNew();
            }],
            formType: function () { return Enums.FormType.CREATE; }
        },
    })
    .when('/item/edit/:itemId', {
        templateUrl: '/app/item/itemForm.html',
        controller: 'itemFormController',
        resolve: {
            item: ['$route', 'itemRepository', function ($route, itemRepository) {
                return itemRepository.get($route.current.params.itemId);
            }],
            formType: function () { return Enums.FormType.EDIT; },
        },
    });

このようにして、エンティティとフォームアクションのタイプをコントローラーに注入します。同じテンプレートも共有しているので、フォームを保存する場合は、リポジトリ/サービスを使用して呼び出すRESTエンドポイントを決定するか、挿入されたformTypeに応じてコントローラー内で簡単なチェックを行うことができます。

繰り返しのコードを最小限に抑えるための良い習慣はありますか?

私が物事を乾いた状態に保つために使用しているもののいくつか:

サーバーAPIで共通の規則を維持している場合は、データアクセス用の基本ファクトリ/リポジトリ/クラス(呼び出したいものは何でも)を使用して非常に長い道のりを進むことができます。例えば:

GET  -> /{resource}?listQueryString     // Return resource list
GET  -> /{resource}/{id}                // Return single resource
GET  -> /{resource}/{id}/{resource}view // Return display representation of resource
PUT  -> /{resource}/{id}                // Update existing resource
POST -> /{resource}/                    // Create new resource
etc.

次に、基本リポジトリクラスを返すAngularJsファクトリを使用し、それをabstractRepositoryと呼びます。次に、リソースごとに、abstractRepositoryからプロトタイプ的に継承する特定のリソースの具象リポジトリを作成します。そのため、abstractRepositoryからすべての共有/ベース機能を継承し、リソース固有の機能を具象リポジトリに定義します。このようにして、データアクセスコードの大部分をabstractRepositoryで定義できます。 Restangularを使用した例を次に示します。

abstractRepository

app.factory('abstractRepository', [function () {

    function abstractRepository(restangular, route) {
        this.restangular = restangular;
        this.route = route;
    }

    abstractRepository.prototype = {
        getList: function (params) {
            return this.restangular.all(this.route).getList(params);
        },
        get: function (id) {
            return this.restangular.one(this.route, id).get();
        },
        getView: function (id) {
            return this.restangular.one(this.route, id).one(this.route + 'view').get();
        },
        update: function (updatedResource) {
            return updatedResource.put();
        },
        create: function (newResource) {
            return this.restangular.all(this.route).post(newResource);
        }
        // etc.
    };

    abstractRepository.extend = function (repository) {
        repository.prototype = Object.create(abstractRepository.prototype);
        repository.prototype.constructor = repository;
    };

    return abstractRepository;
}]);

具体的なリポジトリ、例として顧客を使用しましょう:

app.factory('customerRepository', ['Restangular', 'abstractRepository', function (restangular, abstractRepository) {

    function customerRepository() {
        abstractRepository.call(this, restangular, 'customers');
    }

    abstractRepository.extend(customerRepository);
    return new customerRepository();
}]);

このベースリポジトリパターンを使用すると、ほとんどのCRUDコントローラーも多くの共通コードを共有するため、通常、コントローラーが継承するベースCRUDコントローラーを作成します。ベースコントローラーのアイデアが気に入らない人もいますが、私たちの場合はそれも役立っています。

11
Beyers

最初の質問に対する答えは、おそらく特定の状況によって異なります。

2つのコントローラーがかなりの量の操作を共有し、1つまたは2つの関数の動作を変更する必要がある場合は、どうしてですか。おそらく最もエレガントな解決策ではありませんが、うまくいくものは何でもねえ。

多くまたはすべてのコントローラー操作の動作が「$ scope.mode」に依存する場合は...注意が必要です。それは危険な道のようです。

Angularサービスは、コントローラー間のコードレプリケーションを最小限に抑えるという点で常に役に立ちました。 「反復コードを最小限に抑えるためのグッドプラクティス」があれば、それはサービスだと思います。これらはアプリに対してグローバルであり、問​​題なく複数のコントローラーに挿入できます。

お役に立てば幸いです。

1
aragacalledpat