1
votes

we register custom-validation-methods for custom-form-elements via an extra-directives:

<ng-form name="validatorTestForm">
    <our-input-directive name="validatorTest"
                         ng-model="ourModel"/>
    </our-input-directive>
    <our-validator-directive name="validatorTest"
                             form="validatorTestForm"
                             ng-model="ourModel">
    </our-validator-directive>
</ng-form>

It gets all the information via attributes to know which input in which form to validate; then we connect it like that by initiating the directive: (stripped down version)

registerValidator(ourModel.form, 'validatorTest');

function registerValidator(form, inputName) {
    var validationModel = form[inputName];

    validationModel.$validators.testValidator = function (modelValue) {
        // validate to true when there are more then two characters entered
        return modelValue.length > 2;
    };
}

The our-input-directive is quite simple:

angular.directive('ourInputDirective', function() {
    return {
        restrict: 'E',
        template: '<input type="text" ng-model="model">',
        scope: {
            model: '=?ngModel'
        }
    }
});

So we run it, Angular does its magic and adds tons css-classes to the form-element and the input-element and when we input sth. into the input, it is properly triggering the validation. The form-element gets a css-class 'ng-valid' when it's valid and 'ng-invalid' when it's not.

The input howewer, just has the class 'ng-valid' and never becomes invalid!
So why is that and how can I change it, to reflect the model-changes on the inputs css-classes?


We want to utilize the 'ng-invalid' class to change the style of the input.

3
I'm assuming the validation is just an example, if it's not then you can just use a normal text input and use the attribute minlength. - George
Yes, we want to be able to add all kind of custom validation-methods via this directive. - MaxBoehme

3 Answers

1
votes

Use ng-model https://docs.angularjs.org/api/ng/directive/ngModel

ngModel is responsible for:

  • Binding the view into the model, which other directives such as input, textarea or select require.
  • Providing validation behavior (i.e. required, number, email, url).
  • Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
  • Setting related css classes on the element (ng-valid, ng-invalid, ng-dirty, ng-pristine, ng-touched, ng-untouched, ng-empty, ng-not-empty) including animations.
  • Registering the control with its parent form.

Here's a worknig plnkr in the way you do it. https://plnkr.co/edit/yWlZln2TekdCAhrZ6iEG?p=preview

function customValidator() {
   var directive = {
      require: '^form',
      link: link
   };
   return directive;

   function link(scope, element, attrs, formCtrl) {
      modelCtrl = formCtrl[attrs['name']];
      modelCtrl.$validators.testValidator = function (modelValue, viewValue) {
        var value = modelValue || viewValue;
        if(modelCtrl.$isEmpty(value)){
          return false;
        }
        return value.length > 2;
      };
   }
}
0
votes

As suggested by krutkowski86 try using a ng-model directive instead of the way you are doing it, an example is below

<ng-form name="validatorTestForm">
    <input type="text" name="validatorTest" ng-model="MyVar" validator/>
</ng-form>


angular.module('yourModule').directive('validator', validator);

function validator() {
   var directive = {
      require: 'ngModel',
      link: link
   };
   return directive;

   function link(scope, element, attrs, ngModel) {
      ngModel.$validators.testValidator = function (modelValue) {
      // validate to true when there are more then two characters entered
      return modelValue.length > 2;
      };
   }
}

Please see my Plunker for an example https://plnkr.co/edit/mErINFdPt0odIOdu4Em2?p=preview

0
votes

After some testing we figured out the problem:

Although the 'our-validator-directive' was using the ngModel of the input, it was not using the instance of the ngModel! That was caused by an isolated scope on the directive which contains the input. (Which I did not add in the example, because never thought of it as a problem ...) Therefore changes on the ngModel of the 'our-validator-directive' did not bubble up to the original one.

You really have to link to the original one, what is easily achived with:

ngModelCtrl = form[nameOfTheInput]

Instead of using the required ngModel, which get passed into the validators directive.

[ I have edit the example. ]