Let's say I have the following (very simple) data structure:
$scope.accounts = [{ percent: 30, name: "Checking"}, { percent: 70, name: "Savings"}];
Then I have the following structure as part of a form:
<div ng-repeat="account in accounts"> <input type="number" max="100" min="0" ng-model="account.percent" /> <input type="text" ng-model="account.name" /> </div>
Now, I want to validate that the percents sum to 100 for each set of accounts, but most of the examples I have seen of custom directives only deal with validating an individual value. What is an idiomatic way to create a directive that would validate multiple dependent fields at once? There are a fair amount of solutions for this in jquery, but I haven't been able to find a good source for Angular.
EDIT: I came up with the following custom directive ("share" is a synonym for the original code's "percent"). The share-validate directive takes a map of the form "{group: accounts, id: $index}"
as its value.
app.directive('shareValidate', function() { return { restrict: 'A', require: 'ngModel', link: function(scope, elem, attr, ctrl) { ctrl.$parsers.unshift(function(viewValue) { params = angular.copy(scope.$eval(attr.shareValidate)); params.group.splice(params.id, 1); var sum = +viewValue; angular.forEach(params.group, function(entity, index) { sum += +(entity.share); }); ctrl.$setValidity('share', sum === 100); return viewValue; }); } }; });
This ALMOST works, but can't handle the case in which a field is invalidated, but a subsequent change in another field makes it valid again. For example:
Field 1: 61 Field 2: 52
If I take Field 2 down to 39, Field 2 will now be valid, but Field 1 is still invalid. Ideas?
Prerequisites: Basic knowledge in Angular Reactive Forms. Angular provides FormControl validation in order to determine whether a form field is valid or not. These form control validation helps to determine the validity of a form field with some predetermined rules.
In simple words, making sure our data is correct by using multiple fields to check the validity of another. In fancier terms, this process is called Cross Field Validation. Sanity checking your dataset for data integrity is essential to have accurate analysis and running machine learning models.
ValidatorFnlinkA function that receives a control and synchronously returns a map of validation errors if present, otherwise null. interface ValidatorFn { (control: AbstractControl<any, any>): ValidationErrors | null }
Ok, the following works (again, "share" is "percent"):
app.directive('shareValidate', function () { return { restrict: 'A', require: 'ngModel', link: function(scope, elem, attr, ctrl) { scope.$watch(attr.shareValidate, function(newArr, oldArr) { var sum = 0; angular.forEach(newArr, function(entity, i) { sum += entity.share; }); if (sum === 100) { ctrl.$setValidity('share', true); scope.path.offers.invalidShares = false; } else { ctrl.$setValidity('share', false); scope.path.offers.invalidShares = true; } }, true); //enable deep dirty checking } }; });
In the HTML, set the attribute as "share-validate", and the value to the set of objects you want to watch.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With