The corner function setValidity, resulting in modelValue not being updated

I am having major problems with the form. Here is what I did.

I snatched this cool directive from here: https://github.com/TheSharpieOne/angular-input-match

It looks like this:

directive('match', function () { return { require: 'ngModel', restrict: 'A', scope: { match: '=' }, link: function(scope, elem, attrs, ngModel) { scope.$watch(function() { return (ngModel.$pristine && angular.isUndefined(ngModel.$modelValue)) || scope.match === ngModel.$viewValue; }, function(currentValue, previousValue) { ngModel.$setValidity('match', currentValue); }); } }; }); 

Essentially, this directive oversees the element that it is bound to the model value and compares it with the model value in the match attribute.

So ... for example, below we see if both passwords match:

 Password: <input ng-model="password" type="password" /> Confirm: <input ng-model="passwordConfirm" type="password" match="password" /> 

This directive seems to work, as it sets ng-valid-match and ng-invalid-match to match accordingly.

However, once it is set to invalid, the passwordConfirm model will never be updated again. I made a ton of console.loggin looking at ngModel in the directive, and here is what it looks like when both passwords match:

 Constructor {$viewValue: "asdf", $modelValue: undefined, $validators: Object, $parsers: Array[0], $formatters: Array[0]…} $$debounceViewValueCommit: function (trigger, revalidate) { $$invalidModelValue: "asdf" $$lastCommittedViewValue: "asdf" $$runValidators: function (modelValue, viewValue) { $$validityState: ValidityState $$writeModelToScope: function () { $commitViewValue: function (revalidate) { $dirty: true $error: Object $formatters: Array[0] $invalid: false $isEmpty: function (value) { $modelValue: undefined $name: "passwordConfirmation" $parsers: Array[0] $pristine: false $render: function () { $rollbackViewValue: function () { $setPristine: function () { $setTouched: function () { $setUntouched: function () { $setValidity: function (validationErrorKey, isValid) { $setViewValue: function (value, trigger, revalidate) { $touched: true $untouched: false $valid: true $validate: function () { $validators: Object $viewChangeListeners: Array[0] $viewValue: "asdf" __proto__: Object 

Note that the value of $ viewValue is correct, but the value of $ modelValue is specified as undefined, and $ invalidModelValue still matters.

Here is what html looks like again when both passwords match:

 <input type="password" class="form-control ng-isolate-scope ng-dirty ng-valid-required ng-valid ng-valid-match ng-touched" id="passwordConfirmation" name="passwordConfirmation" placeholder="Confirm your password" ng-model="passwordConfirmation" required="" match="password" style=""> 

Am I missing something? I worked in circles several times.

+6
source share
3 answers

It seems like using $ setValidity is not the way to go. I found this question that offers a different solution using $ validators and $ validate (), and this works fine for me. The new code is as follows:

 directive('match', function () { return { require: 'ngModel', restrict: 'A', scope: { match: '=' }, link: function(scope, elem, attrs, ngModel) { scope.$watch('match', function(pass){ ngModel.$validate(); }); ngModel.$validators.match = function(modelValue, viewValue){ var value = modelValue || viewValue; var match = scope.match; return value === match; }; } }; }); 
+3
source

In a recent update , a change was made to the way $modelValue based on the validity of the field. If the field is invalid, $modelValue will be set to undefined , and the new $$invalidModelValue attribute will be populated with a value.

As a solution to work with 1.2. * and 1.3. * I came up with the following:

  .directive('match', function () { return { require: 'ngModel', restrict: 'A', scope: { match: '=' }, link: function(scope, elem, attrs, ctrl) { scope.$watch(function() { modelValue = ctrl.$modelValue || ctrl.$$invalidModelValue; return (ctrl.$pristine && angular.isUndefined(modelValue)) || scope.match === modelValue; }, function(currentValue) { ctrl.$setValidity('match', currentValue); }); } }; }); 

Plunkr

Although this solution works with both versions, 1.3. * has a new pipeline $validators , which is recommended for the new version.

+6
source

Perhaps this is due to the fact that you are using

 scope: { match : "=" } 

This creates an isolated scope for your directive and is not herite from the parent scope where your ngModel is located.

I suggest trying to remove this part of the scope of your directive and access it from the attributes.

This will become something like:

 directive('match', function () { return { require: 'ngModel', restrict: 'A', link: function(scope, elem, attrs, ngModel) { scope.match = attrs.match; scope.$watch(function() { return (ngModel.$pristine && angular.isUndefined(ngModel.$modelValue)) || scope.match === ngModel.$viewValue; }, function(currentValue, previousValue) { ngModel.$setValidity('match', currentValue); }); } }; }); 
+1
source

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


All Articles