Toggle $ setValidity after model change

I am creating an Angular registration form with three inputs: email , password and passwordConfirm . My controller looks like this:

 app.controller('SignupController', function ($scope, User) { $scope.user = {}; $scope.signup = function() { User.save($scope.user, function(success) { // TODO }, function(error) { if (error.status === 422) { error.data.errors.forEach(function(item) { $scope.signupForm[item.field].$setValidity(item.error, false); }); } }); }; }); 

What it is - sending a request to my API when a user submits a registration form. If response 422 returned (which means validation errors), I scroll through them and set the corresponding inputs to invalid data depending on the returned API.

Let's look at an example of an already registered email address. I am showing a validation error in my view as follows:

 <small class="error" ng-show="signupForm.email.$error.exists">Email address taken, please use another</small> 

All this works fine, but my user is now stuck, because when they try to change the email address to another, the validity of the email field does not change to allow them to resubmit the form (I disabled the submit button based on the validity of the form).

Basically, I need the validation property (in this case exists ) to be reset to true after the user changes the input model. What is the best way for me to do this?

Edit: A little brain wave hit me after posting, I added this to my controller:

 $scope.$watch('user.email', function() { // Reset exists validation property back to true $scope.signupForm.email.$setValidity('exists', true); }); 

which seems to work. When the user changes the value of the model after the input has been set as invalid, he will return it to action. But this does not seem to me the best way to do this. Does anyone know better?

+5
source share
2 answers

I also struggled with this problem. After reading your post, I came up with a possible solution - create a directive that looks at the change model and reset the state of reality to the change (basically what you suggested, but put in the general directive)

 angular.module('app').directive('resetValidityOnChange', function () { return { restrict: 'A', require: 'ngModel', link: function (scope, iElem, iAttrs, ngModelCtrl) { ngModelCtrl.$viewChangeListeners.push(function () { ngModelCtrl.$setValidity(iAttrs['resetValidityOnChange'], true); }); } } } 

You will need to add this directive to the input you would like to use reset, for example:

 <input type="text" ng-model="vm.email" reset-validity-on-change="exists" /> 
0
source

You raised a very interesting question. I think with a little trick you can do this without using $ watch.

You will need a small use-form-error directive that helps you create complex validations.

An example of how you can use it in your case, see jsfiddle

 angular.module('ExampleApp', ['use']) .controller('ExampleController', function($scope) { $scope.errorsFromAjax = null; $scope.simulateSubmit = function() { $scope.errorsFromAjax = { 'testVal': 'used' }; } }); 
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <script src="https://cdn.rawgit.com/Stepan-Kasyanenko/use-form-error/master/src/use-form-error.js"></script> <div ng-app="ExampleApp"> <div ng-controller="ExampleController"> <div ng-form="testForm"> <label>Test value</label> <input ng-model="testVal" name="testVal" use-form-error="{{errorsFromAjax.testVal}}" use-error-expression="errorsFromAjax.testVal && testForm.$pristine"> <pre>errors: {{testForm.testVal.$error|json}}</pre> <span ng-show="testForm.testVal.$error[errorsFromAjax.testVal]" class="errors">You have error!</span> <button ng-disabled="testForm.$invalid" ng-click="simulateSubmit(); testForm.$setPristine()"> Simulate "Submit" </button> </div> </div> </div> 
0
source

Source: https://habr.com/ru/post/1216434/


All Articles