Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have a registration form and I want to do live input validation for emails that have already been registered in the database.

I have the directive working so that it fires on every change to the input box, but I'm having trouble getting Angular to set the proper .error CSS classes from within the scope.$watch function.

Here is my markup:

<form ng-app="mainApp" id="signup_form" name="signup_form" ng-controller="signupController" ng-submit="submit()" novalidate >
                    <fieldset>
                        <legend>Create New Account</legend>
                        <div class="control-group" ng-class="{ error: signup_form.username.$invalid }">
                            <label class="control-label" for="username">Username</label>
                            <div class="controls">
                                <input type="text" placeholder="Username" name="username"                           
                                ng-model="username" 
                                ng-minlength=3 
                                ng-maxlength=20 required />
                            </div>
                        </div>
                        <div class="control-group" ng-class="{ error: signup_form.email.$invalid}">
                            <label class="control-label" for="email">Email</label>
                            <div class="controls">
                                <input type="text" placeholder="Email" name="email" 
                                ng-model="email"
                                required 
                                uniqueaddress/>         
                            </div>
                        </div>          
                            <ul>
                                <li ng-show="signup_form.$error.required" class="error">Field is required.</li>
                                <li ng-show="signup_form.$error.minlength" class="error">Field must at least 3 characters</li>
                                <li ng-show="signup_form.$error.maxlength" class="error">Field is too long.</li>
                                <li ng-show="signup_form.$error.uniqueaddress" class="error">Email is already in use</li>
                            </ul>
                    </fieldset>
                    <button type="submit" ng-disabled="signup_form.$invalid" class="btn">Submit</button>
            </form>

Notice the directive attribute 'uniqueaddress' on the second input box. Here is my directive for uniqueaddress:

mainApp.directive('uniqueaddress', function() {
    return {
        restrict: 'A',
        link: function (scope, element, attrs, ctrl) 
        {
            var isEmailValid = false;
            var isEmailValid = scope.$watch(attrs.ngModel, function (email) 
            {
                if(email == 'test')
                    scope.signup_form.$setValidity('uniqueaddress', false);
                else
                    scope.signup_form.$setValidity('uniqueaddress', true);
            });     
        }
    };
});

And here is a fiddle of demonstarting the issue: http://jsfiddle.net/k4Cty/10/

Type in any 3 character string and the validation works fine for the username field. For the email field, if you type in the string 'test', the validation fires and the <li> item tagged with ng-show="signup_form.$error.uniqueaddress" appears however the .error class is not being set for <div class="control-group"> because it does not go red indicating an validation error. It seems to setting the .error class for the default ng-minlength and required directives are firing but not for uniqueaddress. What am I doing wrong here?

share|improve this question
add comment

1 Answer

up vote 1 down vote accepted

This fiddle takes yours and drops in a pretty standard approach for adding validation using a directive. Main points:

  1. require the element's ngModel controller, where you will wire in your validation.
  2. Places a function at the beginning of array of $parsers to perform validation when the value is parsed from the DOM.
  3. Places a similar function at the beginning of the array of $formatters to perform validation when the DOM is updated from the model.

See this article ("Custom Validation") for more info on how validators work.

You should not try to access the containing form's $setValidity() function. That approach is undocumented and has limited reusability. You also want to target the field whose validity you want to check rather than the type of error. Finally formname.$dirty is your friend. I think angularJS validators are a bit eager, as it's annoying to have validators giving you error feedback as you are entering a value, and hate seeing errors all over the place when you haven't even filled a form out yet, so anything you can do to make it look less panicky.

share|improve this answer
    
I'm new to Angular and this is good stuff. I had not gotten into $parsers and $formatters yet so I will need to look into these. All the tutorials/blogs I had found used some form of $setValidity so it led me to believe that was the proper way to perform the validation. Thanks for the quick response! –  Josh Dec 11 '13 at 15:03
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.