Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

angular: Validate multiple dependent fields

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?

like image 560
TG-T Avatar asked Sep 08 '13 09:09

TG-T


People also ask

What is cross field validation in angular?

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.

What is cross field validation?

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.

What is ValidatorFn in angular?

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 }


1 Answers

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.

like image 112
TG-T Avatar answered Oct 08 '22 15:10

TG-T