2013-10-15 3 views
5

私はAngularJSのv1.2.0 rc2を使用しており、複数のコントローラに共通の機能を提供する最も良い方法が何であるかを知りたいと考えています。

Iモデル編集私はすべてのコントローラで使用する次の検証機能があります。

$scope.canSave = function (formController) { 
    return formController.$dirty && formController.$valid; 
}; 

$scope.validationClasses = function (modelController) { 
    return { 
     'has-error': modelController.$invalid && modelController.$dirty, 
     'has-success': modelController.$valid && modelController.$dirty 
    }; 
}; 

私は私のコントローラを維持したいが、次のように私は工場を定義したドライ:

angular.module('myModule', []) 
    .factory('validationFactory', [function() { 
     return { 
      validationClasses: function (modelController) { 
       return { 
        'has-error': modelController.$invalid && modelController.$dirty, 
        'has-success': modelController.$valid && modelController.$dirty 
       }; 
      }, 
      isFormValid: function (formController) { 
       return formController.$dirty && formController.$valid; 
      } 
     }; 
    }]); 

は当初、私は次のようにそれを必要とコントローラーに工場を混入:

$scope.canSave = validationFactory.isFormValid; 

$scope.validationClasses = validationFactory.validationClasses; 

しかし、私は次のように私は、モジュールのrunメソッドで$ rootScopeにそれらを追加することができます実現:

angular.module('myModule', []) 
    .run([ 
     '$rootScope', 
     'validationFactory', 
     function ($rootScope, validationFactory) { 
      $rootScope.canSave = $rootScope.canUpdate = validationFactory.isFormValid; 
      $rootScope.validationClasses = validationFactory.validationClasses; 
     }]); 

今、彼らは無差別にすべてのコントローラで利用可能であり、行うには少ない配線アップがあります。次のように

機能がビューテンプレートで使用されています

<form name="questionForm" novalidate> 
    <div class="form-group" ng-class="validationClasses(questionForm.question)"> 
     <label for="questionText" class="control-label">Text</label> 
     <input type="text" ng-model="question.text" name="question" 
       id="questionText" class="form-control" required/> 
     <span ng-show="questionForm.question.$error.required" 
       class="help-block">Question text is required</span> 
    </div> 
    ... 
    <div class="form-group" ng-switch on="action"> 
     <button type="button" ng-switch-when="New" ng-click="save()" 
       ng-disabled="!canSave(questionForm)" 
       class="btn btn-primary">Save</button> 
     <button type="button" ng-switch-default ng-click="update()" 
       ng-disabled="!canUpdate(questionForm)" 
       class="btn btn-primary">Update</button> 
     <button type="button" ng-click="cancel()" 
       class="btn btn-default">Cancel</button> 
    </div> 
</form> 

私の質問は以下のとおりです。

  1. 私は$ rootScopeに共通の機能を追加することは避けるべき?もしそうなら、落とし穴は何ですか?
  2. 必要な場合にのみ共通の機能を混在させる方が良いでしょうか?
  3. 同じ結果を達成するためのより良い方法はありますか?

    ソリューション更新

私はそれについての異臭を持っていた$ rootScopeに機能を追加するのではなく、カスタムディレクティブを使用することにしました。

私は、カスタムので、マークアップは次のようになりますvalidation-class-for="<input.name>"disabled-when-invalid属性作成:

<div class="form-group" validation-class-for="question"> 
    <label for="questionText" class="control-label">Text</label> 
    <input type="text" ng-model="question.text" name="question" 
      id="questionText" class="form-control" required/> 
    <span ng-show="questionForm.question.$error.required" 
      class="help-block">Question text is required</span> 
</div> 

<button type="button" ng-click="save()" disabled-when-invalid 
    class="btn btn-primary">Save</button> 

ディレクティブは単にフォーム祖先を必要とし、状態を判断するための機能を見て。

angular.module('myModule', []) 
    .directive('validationClassFor', function() { 
     return { 
      require: '^form', 
      link: function (scope, element, attributes, formController) { 
       scope.$watch(function() { 
        var field = formController[attributes.validationClassFor]; 
        if (field.$invalid && field.$dirty) { 
         element.removeClass('has-success').addClass('has-error'); 
        } else if (field.$valid && field.$dirty) { 
         element.removeClass('has-error').addClass('has-success'); 
        } else { 
         element.removeClass('has-error').removeClass('has-success'); 
        } 
       }); 
      } 
     }; 
    }) 
    .directive('disabledWhenInvalid', function() { 
     return { 
      require: '^form', 
      link: function (scope, element, attributes, formController) { 
       scope.$watch(function() { 
        return formController.$dirty && formController.$valid; 
       }, function (value) { 
        element.prop('disabled', !value); 
       }); 
      } 
     }; 
    }); 

これで、検証工場は必要ありません。

答えて

1

どのようにこのvalidationFactoryを使用していますか?送信ボタンの外観を変更するのですか?その場合は、ボタン自体のカスタムコンポーネントを作成して、コンポーネントがvalidationFactoryを参照するようにすることをお勧めします。

+0

私は、保存/更新ボタンが無効になっているかどうか、およびフォームグループに適用されているCSSクラスを制御する機能を使用しています。 – gwhn

2

ロジックを共有するスコープを使用することはお勧めしません。これは再利用性を低下させ、テストするときに影響を与えます。

  • 私は、次のいずれかの方法をお勧めします:一般的なロジックを抽出するためにhttp://ejohn.org/blog/simple-javascript-inheritance/: あなたはクラス拡張を使用することができます。
  • 有効なリスナーからの「有効」のような、状態を切り替えるイベントをブロードキャストする角度のメッセージングを使用できます。
  • インターセプターを使用して、いくつかの条件に基づいてバックエンド要求を防ぐことができます。
+0

私はあなたがテスト容易性への影響について良い点を作ったと思います。 TBH私はそれがコードの匂いだと思ったので質問に尋ねました。 – gwhn

関連する問題