1
votes

I have the following code/plunkr and for some reason the form.name.$invalid is always true (see the span just after the input box). Angular's documentation doesn't say much about how the $invalid value is set. I have a hunch it has something to do with in the javascript I have ctrl.$error.taken = true/false and just having an object on the $error object set's $invalid to true. Can someone who knows how angular works behind the scenes help me out?

I want the "Name must be alpha-numeric" error to display if the name doesn't match the regex, but I want the "Name is already taken" error to display if the name is one from the list. I also what the text "error" to display if the field is one of those two errors. All of these things are working except the word "error" is always displayed. I'm trying to follow angular's standards of using $invalid.

View:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Example - example-forms-async-validation-production</title>


  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
  <script src="script.js"></script>
</head>
<body ng-app="form-example1">
  <form name="form" class="css-form" novalidate>
  <div>
    Username: 
    <input type="text" ng-model="name" name="name" username /> 
        <span ng-show="form.name.$invalid">error</span>
    <br />{{name}}<br />
    <span ng-show="form.name.$error.badContent">Name must be alpha-numeric</span>
    <span ng-show="form.name.$error.taken">Name is already taken!</span>
  </div>
</form>
</body>
</html>

Script:

(function(angular) {
  'use strict';
var app = angular.module('form-example1', []);

var NAME_REGEXP = /^([a-zA-Z0-9])*$/;
app.directive('username', function() {
  return {
    require: 'ngModel',
    link: function(scope, elm, attrs, ctrl) {
      var names = ['Jim', 'John', 'Jill', 'Jackie'];

      ctrl.$validators.username = function(modelValue, viewValue) {
        if (ctrl.$isEmpty(modelValue)) {
          return true; // consider empty model valid
        }

        ctrl.$error.taken = names.indexOf(modelValue) > -1;
        ctrl.$error.badContent = !NAME_REGEXP.test(modelValue);

        return !ctrl.$error.taken && !ctrl.$error.badContent;
      };
    }
  };
});
})(window.angular);

Plunkr: https://plnkr.co/edit/LBRR14PpjAQigafOVTgQ?p=preview

1

1 Answers

2
votes
  1. Use separate directives one to validate alphanumeric, and one for the username already taken issue.
  2. $ctrl.validators.alphaNumeric exposes $error.alphaNumeric on the FormController. You don't have to manipulate the value on $error.xxx, it is set automatically based on the validator's return value.
  3. Please check the plunkr.
  4. Also refer to https://code.angularjs.org/1.5.8/docs/api/ng/type/ngModel.NgModelController Though I have not verified this, but I believe you now should have ng-invalid-alpha-numeric error class, owing to the fact that now form.$error.alphaNumeric is set.

JS

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

app.controller('MainCtrl', function($scope) {
  $scope.model = {};
});

app.directive('validateAlphaNumeric', function () {

  var REGEX = /^([a-zA-Z0-9])*$/;

  return {
    require: 'ngModel',
    link: function (scope, element, attrs, ctrl) {

      ctrl.$validators.alphaNumeric = function (modelValue, viewValue) {

    if (REGEX.test(viewValue)) {
      return true
    }
    return false;
      };

    }
  };
});

app.directive('validateUserNotTaken', function () {

  return {
    require: 'ngModel',
    link: function (scope, element, attrs, ctrl) {
      var names = ['Jim', 'John', 'Jill', 'Jackie'];
      ctrl.$validators.userNotTaken = function (modelValue, viewValue) {

    if (names.indexOf(modelValue) == -1) {
      return true
    }
    return false;
      };

    }
  };
});

HTML

<body ng-controller="MainCtrl">
    <form name="myForm">
      <input type="text" validate-alpha-numeric validate-user-not-taken ng-model="model.value1">
      <p ng-if="myForm.$error.alphaNumeric">Should be alphanumeric</p>
      <p ng-if="myForm.$error.userNotTaken">User Exists!</p>
      <p ng-if="myForm.$error.alphaNumeric || myForm.$error.userNotTaken">Error</p>
     </form>
  </body>

Working plunkr: https://plnkr.co/edit/MZ7DMW?p=preview