Директива по проверке формы AngularJS для отображения ошибок ввода

Мне нужно создать директиву проверки для автоматического отображения всех входных ошибок для каждого входа. Эта директива проверки должна показывать все ошибки в текущий момент, и список ошибок должен автоматически обновляться во время ввода пользователем.

Мне нужно показать все ошибки для ввода, если вход грязный, а не пустой и недействительный. Мне нужно добавить все ошибки в элемент html возле этого элемента ввода.

Например, если вход имеет тип = "email" и ng-minlength = "5", и пользователь набрал "abc". Мне нужно показать такие ошибки рядом с этим вводом: "Недействительный адрес электронной почты; Введите не менее 5 символов;

Например, если вход имеет тип = "число" attr и min = "200", а min-model = "minnumber" и модель minnumber, установленная на "300", и пользователь напечатал "100". Мне нужно показать такие ошибки рядом с этим input: 'Введите минимальное число 500; Должно быть больше Min Number; '

Также мне нужно обновить все сообщения об ошибках для ввода в предыдущем примере, если обновлена ​​соответствующая модель (параметр min-model).

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 с некоторым кодом для тестирования.

P.S. Нечто похожее делается с UI-Utils, но их директива не дает возможности устанавливать похожие сообщения об ошибках в одном месте.

Ответ 1

Я хочу предложить посмотреть этот пост в этом сообщении, автор объясняет, как достичь ваших целей, и вы можете глубоко погрузиться в код. ссылка

пример из этого сообщения с сообщением об ошибках

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: '' };
  }
});

Ответ 2

Посмотрите директиву 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 и они автоматически отображаются в пользовательском интерфейсе.

Ответ 3

Вот шаблон, который я использовал (с 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>

Пояснение:

Атрибут number в теге <input name="value"> запускает директиву, которая вызывает вызов ngModel validator 'number' и устанавливает/отменяет value.$error.number.

Если установлено value.$error.number, класс has-error применяется к form-group, поэтому он отображает красное поле ввода и выводится справочное сообщение.

Ответ 4

all input errors for each input automatically

Лично я вижу больше минусов, чем профи из этой фразы.

1. Скрытие сообщений об ошибках в javascript из html.

  • Я думаю, что лучше показать столько информации. насколько это возможно разработчикам с html в понятной форме,
    и я считаю, что это путь.

2. Добавление сложности для будущих пользовательских сообщений об ошибках.

  • Что делать, если ваш следующий разработчик хочет изменить сообщения об ошибках, Hey, your input is too short.
    Вы хотите, чтобы он отказался от ваших общих сообщений об ошибках? Или, измените его в своем javascript?

  • Что делать, если ваш следующий разработчик добавит свои пользовательские сообщения об ошибках, используя ng-show.
    Тогда у вас будет два сообщения об ошибках, означающие то же самое.
    Тогда вы не позволите это? или ваше общее сообщение об ошибке директивы должно быть скрыто? Или примените это сообщение об ошибке к общему сообщению об ошибке? Если да, то как? Понимаете, он становится сложным.

IMHO, это общее сообщение об ошибке работает только в том случае, если вы очень уверены в следующем:

  • Сообщения об ошибках одинаковы на многих страницах.
  • Сообщения об ошибках никогда не будут меняться в любом случае в будущем.
  • Разработчики html не должны заботиться об ошибках.
  • Пользовательское сообщение об ошибке не разрешено.

Если вы не уверены в упомянутом выше, я бы рекомендовал не создавать общие сообщения об ошибках.