AngularJS form validation directive for showing input errors

守給你的承諾、 提交于 2019-12-31 09:04:04

问题


I need to create a validation directive for showing all input errors for each input automatically. This validation directive should show all errors at current moment and list of errors should be updated automatically while user is typing.

I need to show all errors for input if input is dirty, not empty and invalid. I need to add all errors into html element near this input element.

For example if input have type="email" and ng-minlength="5" and user typed 'abc' I need to show such errors near this input: 'Invalid email; Please enter at least 5 characters;'

For example if input has type="number" attr and min="200" and min-model="minnumber" and minnumber model set to '300' and user typed '100' I need to show such errors near this input: 'Please enter the minimum number of 500; Should be greater than Min Number;'

Also I need to update all errors messages for input in prev example if related model (min-model param) is updated.

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

        }
    };
});

Can you help to make this validation directive?

Or maybe can you point me into the right direction?

Link to JSFiddle with some code for testing.

P.S. Something similar is made with UI-Utils but their directive does not give ability to set similar error messages in one place.


回答1:


I want to suggest look at this post in this post author is explaining how to achieve your goals , and you can deeply dive into the code . link

example from this post showing error messages

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:


Take a look at the ng-messages directive. Its fairly elegant. Example:

<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>

You can then combine it with any form validation. Just place the error messages from the validators onto the elements $error object and they are automatically rendered in your UI.




回答3:


Here is the pattern that I used (with 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);
      };
    }
  };
});

Then I was able to check for errors in the HTML (with Bootstrap 3.3) using this pattern:

<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>

Explanation:

The number attribute in the <input name="value"> tag triggers the directive, which causes the ngModel validator 'number' to be called and to set/unset value.$error.number.

If value.$error.number is set, then the has-error class is applied to the form-group so it displays a red input field and the help message is displayed.




回答4:


all input errors for each input automatically

Personally, I see more cons than pros from that phrase.

1. Hiding error messages into javascript from html.

  • I think it's better to show as much info. as possible to developers with html in a understandable way,
    and I believe it is the way to go.

2. Adding complexity for the future custom error messages.

  • What if your next developer wants to change error messages to, Hey, your input is too short.
    Do you want him to abandon your general error messages? Or, change it in your javascript?

  • What if your next developer add his custom error messages using ng-show.
    Then, you will have two error messages meaning the same.
    Then, will you not allow to have that? or, your general directive error message should be hidden? Or, apply that custom error message into general error message? If so, then how? See, it gets complex.

IMHO, this general error message only works when you are very sure of the following;

  • Error messages are all the same on many many many pages.
  • Error messages will NEVER change in any case in the future.
  • html developers should not care about error messages.
  • No custom error message is allowed.

If you are not sure about the above I mentioned, I would recommend not to create a general error messages.



来源:https://stackoverflow.com/questions/25278251/angularjs-form-validation-directive-for-showing-input-errors

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!