web-dev-qa-db-ja.com

入力エラーを表示するためのAngularJSフォーム検証ディレクティブ

各入力のすべての入力エラーを自動的に表示するための検証ディレクティブを作成する必要があります。この検証ディレクティブは、現在のすべてのエラーを表示し、ユーザーの入力中にエラーのリストが自動的に更新される必要があります。

入力が空で無効ではなく汚れている場合、入力に関するすべてのエラーを表示する必要があります。この入力要素の近くのhtml要素にすべてのエラーを追加する必要があります。

たとえば、入力にtype = "email"およびng-minlength = "5"があり、ユーザーが「abc」と入力した場合、この入力の近くにこのようなエラーを表示する必要があります。少なくとも5文字を入力してください; '

たとえば、入力にtype = "number" attrおよびmin = "200"およびmin-model = "minnumber"およびminnumberモデルが「300」に設定され、ユーザーが「100」と入力した場合、この入力の近くにこのようなエラーを表示する必要があります:最小数の500を入力してください。最小数より大きくする必要があります; '

また、関連するモデル(min-model param)が更新された場合、前の例の入力のすべてのエラーメッセージを更新する必要があります。

var app = angular.module('app', []);

app.controller('appCtrl', function ($scope) {

});

app.directive('validate', function () {
    return {
        restrict: 'A',
        require: 'ngModel', // require:  '^form',

        link: function (scope, element, attrs, ctrl) {
            console.log('======================');
            console.log(scope);
            console.log(element);
            console.log(attrs);
            console.log(ctrl);
            console.log(scope.form.$error);
            angular.forEach(scope.form.$error, function (value, key) {
                console.log('scope.form.$error = ' + key + ': ' + value);
                console.log(value);
            });

        }
    };
});


app.directive('positiveInteger', function () {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ctrl) {
            ctrl.$parsers.unshift(function (viewValue) {
                var INTEGER_REGEXP = /^\d+$/;
                if (INTEGER_REGEXP.test(viewValue)) { // it is valid
                    ctrl.$setValidity('positiveInteger', true);
                    return viewValue;
                } else { // it is invalid, return undefined (no model update)
                    ctrl.$setValidity('positiveInteger', false);
                    return undefined;
                }
            });
        }
    };
});


app.directive('positiveFloat', function () {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ctrl) {
            ctrl.$parsers.unshift(function (viewValue) {
                var FLOAT_REGEXP = /^(?:[1-9]\d*|0)?(?:\.\d+)?$/;
                if (FLOAT_REGEXP.test(viewValue)) { // it is valid
                    ctrl.$setValidity('positiveInteger', true);
                    return viewValue;
                } else { // it is invalid, return undefined (no model update)
                    ctrl.$setValidity('positiveInteger', false);
                    return undefined;
                }
            });
        }
    };
});


app.directive('minModel', function () {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ctrl) {
            ctrl.$parsers.unshift(function (viewValue) {
                if (viewValue > scope[attrs.minModel]) { // it is valid
                    ctrl.$setValidity('minModel', true);
                    return viewValue;
                } else { // it is invalid, return undefined (no model update)
                    ctrl.$setValidity('minModel', false);
                    return undefined;
                }
            });

        }
    };
});

この検証ディレクティブの作成を手伝ってもらえますか?

または多分、私を正しい方向に向けることができますか?

テスト用のコードを含むJSFiddleへのリンク

追伸似たようなものが I-Utils で作成されますが、それらのディレクティブは1つの場所で同様のエラーメッセージを設定する機能を提供しません。

12
webvitaly

この投稿者のこの投稿を見て、あなたの目標を達成する方法を説明することをお勧めします。コードを深く掘り下げることができます。 link

エラーメッセージを示すこの投稿の例

module = angular.module('app', []);

module.directive('showErrors', function($timeout) {
    return {
      restrict: 'A',
      require: '^form',
      link: function (scope, el, attrs, formCtrl) {
        // find the text box element, which has the 'name' attribute
        var inputEl   = el[0].querySelector("[name]");
        // convert the native text box element to an angular element
        var inputNgEl = angular.element(inputEl);
        // get the name on the text box
        var inputName = inputNgEl.attr('name');

        // only apply the has-error class after the user leaves the text box
        var blurred = false;
        inputNgEl.bind('blur', function() {
          blurred = true;
          el.toggleClass('has-error', formCtrl[inputName].$invalid);
        });

        scope.$watch(function() {
          return formCtrl[inputName].$invalid
        }, function(invalid) {
          // we only want to toggle the has-error class after the blur
          // event or if the control becomes valid
          if (!blurred && invalid) { return }
          el.toggleClass('has-error', invalid);
        });

        scope.$on('show-errors-check-validity', function() {
          el.toggleClass('has-error', formCtrl[inputName].$invalid);
        });

        scope.$on('show-errors-reset', function() {
          $timeout(function() {
            el.removeClass('has-error');
          }, 0, false);
        });
      }
    }
  });

module.controller('NewUserController', function($scope) {
  $scope.save = function() {
    $scope.$broadcast('show-errors-check-validity');

    if ($scope.userForm.$valid) {
      alert('User saved');
      $scope.reset();
    }
  };

  $scope.reset = function() {
    $scope.$broadcast('show-errors-reset');
    $scope.user = { name: '', email: '' };
  }
});
13

ng-messagesディレクティブ を見てください。そのかなりエレガント。例:

<form name="myForm">
  <input type="text" ng-model="field" name="myField" required minlength="5" />
  <div ng-messages="myForm.myField.$error">
    <div ng-message="required">You did not enter a field</div>
    <div ng-message="minlength">The value entered is too short</div>
  </div>
</form>

その後、フォーム検証と組み合わせることができます。バリデーターからのエラーメッセージを要素の$ errorオブジェクトに配置するだけで、それらはUIに自動的にレンダリングされます。

11
Brad

私が使用したパターンは次のとおりです(Angular 1.3)で:

app.directive('number', function() {
  var NUMBER_REGEXP = /^(\d+)$/;
  return {
    require: 'ngModel',
    link: function(scope, Elm, attrs, ctrl) {
      ctrl.$validators.number = function(modelValue, viewValue) {
        return NUMBER_REGEXP.test(viewValue);
      };
    }
  };
});

次に、このパターンを使用して、HTMLのエラーを確認することができました(Bootstrap 3.3)。

<form name="form">
  <div class="form-group"
       ng-class="{'has-error': form.value.$dirty && form.value.$error.number}">
    <label for="id_value" class="control-label">Value:</label>
    <div>
      <input type="text" class="form-control" id="id_value" name="value"
             ng-model="model.number" number>
      <p class="help-block" ng-if="form.value.$error.number">Please enter a number</p>
    </div>
  </div>
</form>

説明:

<input name="value">タグのnumber属性はディレクティブをトリガーします。これにより、ngModelバリデーター'number'が呼び出され、value.$error.numberが設定/設定解除されます。

value.$error.numberが設定されている場合、has-errorクラスがform-groupに適用されるため、赤い入力フィールドが表示され、ヘルプメッセージが表示されます。

6
Brent Washburne