HMR
HMR

Reputation: 39250

Validate form control based on other controls, access other control in validate function

I would like to validate email and phone based on the following:

If both email and phone are empty or the value containing them are not valid then both are invalid with message "Please provide either a valid email or phone number."

If the email address is invalid then it's invalid with possibly the above message plus "This is not a valid email address.", same for the phone.

Here is what I got so far:

The template/html:

      <input type="email" name="email" class="form-control"
        id="useredit:email" 
        data-ng-model="userInfo.email"
        data-user-validate='email'
      >
      <span class="glyphicon form-control-feedback"
            data-ng-class="setValidGlyph(userEdit.email,'mail');"
            data-ng-show='!userEdit.email.$pristine'
            data-tooltip-html-unsafe=
              "{{getValidateMessage(userEdit.email,'email');}}"
            data-tooltip-trigger='click'
            data-tooltip-placement='bottom'
            data-tooltip-append-to-body='true'
            ></span>

setValidGlyph comes from appSettings and figures out what glyph to show:

setValidGlyph:function(input,fieldName){
  return {
    'glyphicon-info-sign':input.$error[fieldName] && !input.$pristine
    ,'glyphicon-ok': !input.$error[fieldName] && !input.$pristine
  };
}

getValidateMessage comes from appRules and will show message(s) depending on on what the validator function has set true (see code later).

data-tooltip is ui bootstrap tooltip.

The directive:

angular.module('app').directive('userValidate'
 , ['appSettings', 'appRules', function(appSettings,appRules) {
  return {
    require: 'ngModel',
    link: function(scope, elm, attrs, ctrl) {
      var fn=appRules.user.validate(attrs.userValidate);
      ctrl.$parsers.unshift(
        function(viewValue){
          fn(viewValue,ctrl);
        }
      );
      ctrl.$error.messages=
        appRules.user.validateMessages[attrs.userValidate];
    }
  };
}]);

the apprules:

angular.module('app').factory('appRules'
 , ['appSettings',function(appSettings){
  var appRules = {
    user:{
      validate:function(name){        
        return appRules.user.validateFunctions[name];
      },
      validateFunctions: {
        email:function(viewValue,ctrl){
          //  mail indicates if this box is valid or not used for css
          ctrl.$setValidity('mail'
            , appRules.general.isEmail(viewValue));
          //specific to see if email is valid
          //removed isEmail to make code shorter
          ctrl.$setValidity('invalidEmail'
            , appRules.general.isEmail(viewValue));
        }
      },
      getValidateMessage:function(ctrl,name){
        var ret = [],i=-1,len=ctrl.$error.messages.length;
        while(++i<len){
          if(ctrl.$error[ctrl.$error.messages[i]]){
            ret.push('<p>');
            ret.push(appSettings
              .userFailMessages[ctrl.$error.messages[i]]);
            ret.push('</p>');
          }
        }
        return ret.join('');
      },
      validateMessages: {
        name:['emptyName'],
        email:['invalidEmail','phoneOrEmail']
      }
    }
  };
  return appRules;
}]
);

appSettings.userFailMessages is in appSettings and looks like this:

appSettings.userFailMessages.invalidEmail="Please provide a valid email.";

In appRules.validateFunctions.email I would like to access phone.$pristine and phone.$error but arguments passed are only the current input control and that has no access to the form it's on.

How could I access this? Maybe somewhere in the template I can set the form with:

{{setForm(userEdit);}}

Where userEdit is the name of the form and setForm is a method of appRules but it seems kind of sloppy.

Reason for validation and messages to be in rules and settings is because I am uncomfortable having domain rules and error messages in my template.

Upvotes: 2

Views: 661

Answers (1)

Ben Lesh
Ben Lesh

Reputation: 108471

If you need access to the form in your directive, you need to require it:

require: ['^form', 'ngModel'],
link: function($scope, elem, attrs, ctrls) {
   var form = ctrls[0];
   var ngModel = ctrls[1];

   if(form) {
     // use form to get whatever it is you care about.
     var whatever = form[otherProperty].$error.something;
   }
}

So given the above, you should be able to pass the form controller into your custom validation methods as a third argument, and handle whatever you need.

I hope this helps.

Upvotes: 4

Related Questions