0

EDIT: Below is the working example for anyone looking. I have live validation on the promoCode with the directive that takes in 2 input values.

Hello I'm stuck on a problem. I have 2 inputs, an email and a promo code and one directive that checks if the promo code and associated email are valid. However I am stuck in how to pass in the email value as well. I've got it half way where I am able to check the promo code with a hardcoded email value. Am I going to have to rewrite how I do this check or am I missing something obvious to get the email value? Is this even a right approach? I am new to Angular.

To clarify: The API call happens when the user starts typing in a promo code. Basically how do I grab the email value and send it along to the factory? I've looked and tried scope.$watch and was able to see the values changing for each input but was unable to store it.

I have looked here How to get evaluated attributes inside a custom directive and tried that approach but was getting "undefined" for email and promocode values.

HTML

<input type="text" class="form-control" name="email" id="email" placeholder="Enter Email" maxlength="254" ng-model="registrationData.email" required >
<input type="text" class="form-control" name="promoCode" id="promo-code" placeholder="Parking Program Code" ng-model="registrationData.promo_code" ng-model-options="{ debounce: 500 }" promo-email='registrationData.email' promo-validation>
<div ng-show="validate.promoCode.$touched || validate.promoCode.$dirty">
  <div ng-messages="validate.promoCode.$error" style="color:maroon" role="alert">
  <div ng-message="promoCode">Code invalid</div>
</div>
<div ng-messages="validate.promoCode.$pending">
  <div ng-message="promoCode">Checking promo test...</div>
</div>

Directive

.directive('promoValidation',['isPromoValid', function(isPromoValid)
{ 
  return {
  restrict: 'A',
  require: 'ngModel',
  scope: 
  { 
      promoEmail:'=' 
  },
  link: function(scope, element, attrs, ngModel) {
  element.bind('focus', function() {
    ngModel.$asyncValidators.promoCode = function(promoCode) {
      return isPromoValid(scope.promoEmail, promoCode);
   })
   }
  }}
]);

Factory

.factory('isPromoValid',['$q', '$http', 'SERVICE_BASE', function($q, $http, SERVICE_BASE) {
var apiUrl = SERVICE_BASE + '/users/ValidatePromoCode';
return function(email, promoCode) {
var deferred = $q.defer();
if(!promoCode)
{
  deferred.resolve(); //promoCode is optional so I have this check if the user adds a promoCode then deletes it. It removes the error message
}
else {
  $http.get(apiUrl , {params: { promo_code: promoCode, email: email }}).then(function validPromo(data){
  var isPromoValid = data.data.data.valid;
  if(isPromoValid) {
    deferred.resolve();
  }
  else {
    deferred.reject();
  }
});
   }
    return deferred.promise;
  };
}]);
Community
  • 1
  • 1
Misha
  • 128
  • 1
  • 12
  • You should declare only one `promo-validation` attribute in a wrapper of the inputs. But you will have to change your directive code to detect the changes on the inputs. – c4k Apr 18 '16 at 23:57

1 Answers1

1

You need to change your directive like as-

.directive('promoValidation',['isPromoValid', function(isPromoValid
{ 
  return {
  restrict: 'A',
  require: 'ngModel',
  scope: {
        promoEmail:'='
},
  link: function(scope, element, attrs, ngModel) {
  element.bind('focus', function() {
    //console.log(ngModel.email); 
    //console.log(scope.promoEmail); // pass this email to your validator factory
    ngModel.$asyncValidators.promoCode = isPromoValid;
   })
   }
  }}
]);

On html, use this directive only for promocode input field like as-

<input type="text" class="form-control" name="email" id="email" placeholder="Enter Email" maxlength="254" ng-model="registrationData.email" required >
<input type="text" class="form-control" name="promoCode" id="promo-code" placeholder="Parking Program Code" ng-model="registrationData.promo_code" ng-model-options="{ debounce: 500 }" promo-email='registrationData.email' promo-validation>
<div ng-show="validate.promoCode.$touched || validate.promoCode.$dirty">
  <div ng-messages="validate.promoCode.$error" style="color:maroon" role="alert">
  <div ng-message="promoCode">Code invalid</div>
</div>
<div ng-messages="validate.promoCode.$pending">
  <div ng-message="promoCode">Checking promo test...</div>
</div>

you can improve this code as much as you needed.

  • How does this change the factory? I know I can change it to accept it like isPromoValid(email, promo) but I want to keep it with the ngModel.$async. Isn't that what is responsible for the live validation? – Misha Apr 19 '16 at 13:12
  • Thanks Shail, I was on that track but for some reason I was getting undefined. I was able to grab the email how you suggested and changed the async, I got it working this way. ngModel.$asyncValidators.promoCode = function(value) { var email = scope.promoEmail; return isPromoValid(email, value); – Misha Apr 19 '16 at 14:11