Form validation – Multiple emails

All we need is an easy explanation of the problem, so here it is.

Hi I have a form with a text area that holds multiple emails addresses. How can I validate this in AngularJS, right now it says it is invalid when there is more than one emails. The emails will be comma separated.

<form name="testForm" ng-submit="submit()" novalidate>
     <textarea type="email" multiple rows="3" name="emailInput" placeholder="Email Addresses" ng-model="user.email" required></textarea>    
     <button type="submit" ng-disabled="testForm.$invalid">Email</button>
</form>

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Taking a look at the source (version 1.2.16), it is easy to find out how the validation of a single email takes place:

// This is the regular expression used to validate the value
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-][email protected][a-z0-9-]+(\.[a-z0-9-]+)*$/i;

// A helper function to call $setValidity and return the value / undefined,
// a pattern that is repeated a lot in the input validation logic.
function validate(ctrl, validatorName, validity, value){
  ctrl.$setValidity(validatorName, validity);
  return validity ? value : undefined;
}

// Excerpt from the `input[type="email"]` directive
var emailValidator = function(value) {
  return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
};

ctrl.$formatters.push(emailValidator);
ctrl.$parsers.push(emailValidator);

So, you could make your own directive that validates multiple, comma-searated emails in a similar fashion:

app.directive('multipleEmails', function () {
  // Constants
  var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-][email protected][a-z0-9-]+(\.[a-z0-9-]+)*$/i;

  // DDO
  return {
    restrict: 'A',
    require: 'ngModel',
    link: multipleEmailsPostLink
  };

  // Function Definitions
  function isValidEmail(email) {
    return EMAIL_REGEXP.test(email.trim());
  }

  function multipleEmailsPostLink(scope, elem, attrs, modelCtrl) {
    modelCtrl.$formatters.push(multipleEmailsValidator);
    modelCtrl.$parsers.push(multipleEmailsValidator);

    // Helpers
    function multipleEmailsValidator(value) {
      return validateAll(modelCtrl, 'multipleEmails', value);
    }
  }

  function validateAll(ctrl, validatorName, value) {
    var validity = ctrl.$isEmpty(value) || value.split(',').every(isValidEmail);

    ctrl.$setValidity(validatorName, validity);

    return validity ? value : undefined;
  }
});

See, also, this short demo.

Method 2

Here is a quick and dirty way to do what you need. In your HTML:

<textarea ng-change="validateEmails()" ng-model="user.email" ng-class="user.validation.email.isValid ? 'valid' : 'invalid'">
<div class="errorPanel" ng-show="!user.validation.email.isValid">{{ validation.email.message }}</div>

Alternatively, instead of ng-change you can use ng-blur so that the textarea does not become ‘invalid’ as the user is typing in emails. I’ll leave that up to you, though. Add some CSS styling for textarea.valid, textarea.invalid, div.errorPanel.

And in your controller:

user.validation = {};
user.validation.email = {
  message: '',
  isValid: true
};

$scope.validateEmails = function() {
  var emails = $scope.user.email.split(',');

  var isValid = true;
  for (var i = 0; isValid && i < emails.length; i++) {
    if (!validateEmail(emails[i])) {
      isValid = false;
      user.validation.email.isValid = false;
      user.validation.email.message = 'Email ' + emails[i] + ' does not appear to be a proper email';
    }
  }

}

function validateEmail() {
  // use whatever email validation function you want
}

Hope that helps!

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply