web-dev-qa-db-ja.com

FormControllerからフォームコントロールを取得する

AngularJSフォームの登録済みコントロールをループする方法が必要です。基本的に、私はすべての$ dirtyコントロールを取得しようとしていますが、コントロールの配列はありません(FormControllerには、コントロール自体を含むことに加えて、それぞれが独自のオブジェクトとして、多くの異なるプロパティ/関数があります)。

私はソースコードを見てきましたが、探している配列とまったく同じcontrols配列がFormControllerにあることがわかります。この値にアクセスする方法、またはこのcontrols配列を返す関数を含むようにFormControllerを拡張する方法はありますか?

編集: Plnkr demo

また、技術的にはキー文字列の最初の文字で「$」をチェックできることに気付きましたが、Angularの将来のバージョンでFormController/directiveが変更された場合にはそれを避けたいと思います。

編集2:別の明確化:これのすべての私の目標は、コントロールのリスト全体をループすることによって($ dirty、$ invalid、$ error、$ nameを含まないか、 Formオブジェクトにそのまま存在するその他のプロパティ)、またはFormControllerを拡張し、現在ダーティな(および開始値と等しくない)コントロールのみを返す関数を作成する

編集3:私が探しているソリューションは、さまざまな構造のフォーム/モデルに適用できる必要があります。スコープのモデルはAJAXを介して生成されるため、それらの構造は既に設定されています(AJAXを介して既に受信しているすべてのデータの新しい構造をハードコーディングする必要はありません)。また、このフォーム送信プロセスを複数のフォーム/モデルで使用したいと考えており、オブジェクトモデルの異なるエンティティに適用されるため、それぞれが異なるJSON構造を持っています。これが、FormControllerのcontrolsオブジェクトへのアクセスを取得する方法を選択する理由です(以下のFormControllerからコードを投稿します)。すべてのフィールドのフラット配列を取得できます。

function FormController(element, attrs) {


var form = this,
      parentForm = element.parent().controller('form') || nullFormCtrl,
      invalidCount = 0, // used to easily determine if we are valid
      errors = form.$error = {},
      controls = [];

  // init state
  form.$name = attrs.name || attrs.ngForm;
  form.$dirty = false;
  form.$pristine = true;
  form.$valid = true;
  form.$invalid = false;

  parentForm.$addControl(form);

  // Setup initial state of the control
  element.addClass(PRISTINE_CLASS);
  toggleValidCss(true);

  // convenience method for easy toggling of classes
  function toggleValidCss(isValid, validationErrorKey) {
    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
    element.
      removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).
      addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
  }

  /**
   * @ngdoc function
   * @name ng.directive:form.FormController#$addControl
   * @methodOf ng.directive:form.FormController
   *
   * @description
   * Register a control with the form.
   *
   * Input elements using ngModelController do this automatically when they are linked.
   */
  form.$addControl = function(control) {
    controls.Push(control);

    if (control.$name && !form.hasOwnProperty(control.$name)) {
      form[control.$name] = control;
    }
  };

  /**
   * @ngdoc function
   * @name ng.directive:form.FormController#$removeControl
   * @methodOf ng.directive:form.FormController
   *
   * @description
   * Deregister a control from the form.
   *
   * Input elements using ngModelController do this automatically when they are destroyed.
   */
  form.$removeControl = function(control) {
    if (control.$name && form[control.$name] === control) {
      delete form[control.$name];
    }
    forEach(errors, function(queue, validationToken) {
      form.$setValidity(validationToken, true, control);
    });

    arrayRemove(controls, control);
  };

  // Removed extra code
}

ご覧のとおり、フォーム自体にはcontrols配列がプライベートに使用できます。 FormControllerを拡張してそのオブジェクトを公開できるようにする方法があるかどうか疑問に思っています。または、少なくともプライベート配列を表示できるようにパブリック関数を作成しますか?

29
robert.bo.roth

質問に対する直接的な解決策については、@ lombardoの回答を次のように変更してください。

     var dirtyFormControls = [];
     var myForm = $scope.myForm;
     angular.forEach(myForm, function(value, key) {
         if (typeof value === 'object' && value.hasOwnProperty('$modelValue') && value.$dirty)
             dirtyFormControls.Push(value)                        
     });

配列「dirtyFormControls」には、ダーティなフォームコントロールが含まれます。

また、このトリックを使用して、「必須」検証およびその他すべての検証のフォーム送信時にエラーメッセージを表示することもできます。 submit()関数では、次のようなことを行います。

 if (form.$invalid) {
     form.$setDirty();              
     angular.forEach(form, function(value, key) {
         if (typeof value === 'object' && value.hasOwnProperty('$modelValue'))
             value.$setDirty();                        
     });
    //show user error summary at top of form.
     $('html, body').animate({
         scrollTop: $("#myForm").offset().top
     }, 1000);
     return;
 }

そして、フォームにエラーメッセージが表示されます

    <span ng-messages="myForm['subject-' + $index].$error" ng-show="myForm['subject-' + $index].$dirty" class="has-error">
        <span ng-message="required">Course subject is required.</span>
    </span>

上記のソリューションは、「ng-repeat」などを使用して動的にコントロールを生成した場合に役立ちます。

19
faitha

次のコードを使用して、コントロールを反復できます。

    var data = {};
    angular.forEach(myForm, function (value, key) {
        if (value.hasOwnProperty('$modelValue'))
            data[key] = value.$modelValue;
    });
11
lombardo

コントローラー内から単純に試してください:

$scope.checkForm = function(myFormName){
     console.log(myFormName.$invalid);
}

更新:

<div ng-controller="MyController">
                <form name="form" class="css-form" novalidate>
                    <input type="text" ng-model="user.uname" name="uname" required /><br />
                    <input type="text" ng-model="user.usurname" name="usurname" required /><br />
                    <button ng-click="update(form)">SAVE</button>
                </form>
              </div>

app.controller('MyController',function($scope){
                $scope.user = {};
                $scope.update = function (form){
                    var editedFields = [];
                    angular.forEach($scope.user, function(value, key){
                        if(form[key].$dirty){
                           this.Push(key + ': ' + value); 
                        }

                    }, editedFields);
                    console.log(editedFields);
                }
        });
2
Whisher

私はややまともな解決策を考え出しましたが、それはまだ私が探していたものではありません。文字列からJSONオブジェクトを作成することに関する別の問題からいくつかのコードを回収し、次のことを考え出しました。

基本的に、モデルに関連付けられているのと同じ方法でフィールドに名前を付け、form_submitが呼び出されたときに送信用の新しいオブジェクトを作成しています。

Plnkrデモ

デモでは、フォームフィールドのいずれかを変更してから[送信]をクリックすると、ダーティ値のみが表示されたオブジェクトがポップアップ表示されます。

0
robert.bo.roth