Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

implementing a directive to exclude a hidden input element from validation ($addControl issue)

I'm creating a directive to exclude a hidden input element from validation: http://plnkr.co/edit/Vnwvq2AT7JpgTnoQwGh9?p=preview

app.directive('shownValidation', function() {
    return {
      require: '^form',
      restrict: 'A',
      link: function(scope, element, attrs,form) {
        var control;

        scope.$watch(attrs.ngShow,function(value){
          if (!control){
            control = form[element.attr("name")];
          }
          if (value == true){
            form.$addControl(control);
          }else{
             form.$removeControl(control);
          }
        });
      }
    };
  });

The idea here is if the element is hidden, I will remove the control from the Form so that it will not affect the other input validity. It works fine when I call form.$removeControl(control);, you can test that in the demo by removing the firstname and clicking on the button to hide the field.

But when I click the button again, the form validity is still true even though the firstname is invalid (empty)

I also tried adding form.$setValidity(form.$valid && control.$valid) => the validity state is updated as expected but when I type into the firstname, the validity is still false.

My question is how to solve this problem? Thanks for any replies.

Update:

Thanks to @Michael's answer. Here is the working solution:

app.directive('shownValidation', function() {
  return {
    require: '^form',
    restrict: 'A',
    link: function(scope, element, attrs, form) {
      var control;

      scope.$watch(attrs.ngShow, function(value) {
        if (!control) {
          control = form[element.attr("name")];
        }
        if (value == true) {
          form.$addControl(control);
     //Add a forEach to manually update form validity.Thanks to @Michael's answer
          angular.forEach(control.$error, function(validity, validationToken) {
            form.$setValidity(validationToken, !validity, control);
          });
        } else {
          form.$removeControl(control);
        }
      });
    }
  };
});

Working plunk

like image 918
Khanh TO Avatar asked Feb 05 '14 10:02

Khanh TO


2 Answers

If the control is removed angular updates the validity (from the sources):

  form.$removeControl = function(control) {
    if (control.$name && form[control.$name] === control) {
      delete form[control.$name];
    }
    forEach(errors, function(queue, validationToken) {
      form.$setValidity(validationToken, true, control);
    });

    arrayRemove(controls, control);
  };

If you add the control angular did not update the validity (from the sources):

  form.$addControl = function(control) {
    // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
    // and not added to the scope.  Now we throw an error.
    assertNotHasOwnProperty(control.$name, 'input');
    controls.push(control);

    if (control.$name) {
      form[control.$name] = control;
    }
  };

so we have to do this manually. I guess this way:

if (value == true){
    form.$addControl(control); 
    angular.forEach(control.$error, function(validity, validationToken) {
       form.$setValidity(validationToken, !validity, control);
    });
   }else{
    form.$removeControl(control);
   }
}
like image 137
michael Avatar answered Oct 04 '22 08:10

michael


It seems you are hiding the element using ng-show and thus not submitting the input along with the form.

In this case, we can use ng-if directive in the view in order to remove the element on the fly. This would remove the element and it's validity too.

like image 20
Sagar Ranglani Avatar answered Oct 04 '22 09:10

Sagar Ranglani