How to add an array size check rule in angularjs form?

I have a form with some text input fields and a dynamic list of elements stored in the $ scope area of ​​the controller, with some functions for adding / removing elements in the list. I want to invalidate the form until the list of elements reaches a predetermined length.

So, I created a formRepeat directive that takes an ngModel attribute and then uses ngModelController to cancel the form.

http://plnkr.co/edit/jSFvak?p=preview

This works, but I think this is not the best way to do this, since the directive is not very flexible.

The easiest way would be to invalidate the form in the controller with something like:

$scope.myForm.$valid = false; 

But that will not work.

Is there a better way?

+6
source share
7 answers

Based on plunker . I would use the following $watch function (similar to @NicolasMoise's reaction)

 $scope.$watch('items', function (items) { $scope.myForm.$setValidity('count', items.length >= 5); }, true); 

It is important to set the objectEquality flag to true so that $watch will fire if any of the properties of the object has changed

or, if only a small list (collection) comparison is done, use $watchCollection

 $scope.$watchCollection('items', function (items) { $scope.myForm.$setValidity('count', items.length >= 5); }); 

I'm also out of luck with $setValidity('$valid') or similar

+3
source

The easiest way for me is to specify the length of the array as a hidden number input and put a min check on it. Actually a very clean solution.

 <input style="display: none;" type="number" name="itemsCount" ng-model="items.length" min="{{min}}"> 

Check updated plunker

+7
source

The best way to do this (IMO) is to create a custom directive that uses ngModelController Validators .

Validators are executed every time the model is updated and are used for the validity of the form. Your directive might look something like this:

 angular.module('directiveTest', []).directive('minLength', function() { return { require: 'ngModel', link: function(scope, elm, attrs, ngModel) { scope.minlength = attrs.minLength || 1; ngModel.$validators.minLength = function(modelValue){ /* Assume TRUE when empty, as ngRequired should be used for mandatory values */ return (ngModel.$isEmpty(modelValue)) ? true : (modelValue.length >= scope.minlength); }; } }; }); 

And you can call it from your HTML as follows:

 <input type="text" name="content" ng-list min-length="2" ng-model="content" /> 

You can find a working example on the following Plunker .

+3
source

I do not consider it necessary to use the directive in this case. Just do ng-repeat for the elements and inside your controller something like this

 $scope.$watch('items', function(val){ if(val.length<5){ //$scope.myForm should be available here $scope.myForm.setValidity('$valid'); //add additional form validation ($dirty, setting back to $invalid, etc...) } }) 
+1
source

maybe this is what you are looking for http://docs.angularjs.org/api/ng/type/form.FormController

0
source

I think you can achieve this using the ng class.

Try this, in HTML,

 <html data-ng-app="myApp"> <head> <link data-require=" bootstrap-css@ *" data-semver="3.1.1" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" /> <script data-require=" angular.js@ *" data-semver="1.2.13" src="http://code.angularjs.org/1.2.13/angular.js"></script> <script data-require=" angular-animate@ *" data-semver="1.2.13" src="http://code.angularjs.org/1.2.13/angular-animate.js"></script> <link rel="stylesheet" href="style.css" /> <script src="script.js"></script> </head> <body data-ng-controller="MainCtrl"> <div class="container"> <div class="col-sm-12 col-md-6 col-md-offset-3"> <form name="myForm" ng-class="formClass"> <div class="form-group"> <label>Name</label> <input type="text" name="name" data-ng-model="user.name" class="form-control" required="" /> </div> <div class="form-group"> <label>Country</label> <input type="text" name="country" data-ng-model="user.country" class="form-control" required="" /> </div> <div class="form-group"> <label>Items</label> <br /> <button type="button" class="btn btn-primary" data-ng-click="addItem()">Add</button> <p data-ng-show="items.length < min">I need at least {{min}} items ! (so {{min - items.length}} more would be good)</p> <div data-ng-repeat="item in items"> <button type="button" class="btn btn-danger" data-ng-click="removeItem($index)">Delete</button> <span>{{item}}</span> </div> </div> </form> </div> </div> </body> </html> 

In script.js,

 angular.module('myApp', ['ngAnimate']); angular.module('myApp') .controller('MainCtrl', ['$scope', function ($scope) { $scope.items = []; $scope.min = 5; var _counter = 0; $scope.formClass="invalid"; $scope.addItem = function () { $scope.items.push('item' + _counter); _counter++; $scope.isFormValid(); }; $scope.isFormValid=function(){ if ($scope.items.length < 5) { $scope.formClass="invalid"; } else if ($scope.items.length >=5){ $scope.formClass="valid"; } } $scope.removeItem = function (index) { $scope.items.splice(index, 1); $scope.isFormValid(); }; }]); 

In css file

 body { padding: 16px; background: #555555; } /*.my-form { transition:0.5s linear all; padding: 16px; border-radius: 4px; background: #ffffea; }*/ .invalid { transition:0.5s linear all; padding: 16px; border-radius: 4px; background: #ffffea; background: #ffeaea; } .valid { transition:0.5s linear all; padding: 16px; border-radius: 4px; background: #ffffea; background: #eaffea; } 

Do you want something like that?

Please see plunker

0
source

a little late, but I do it like this:

 <button type="button" class="btn btn-success" ng-disabled="form.$invalid || user.groups.length == 0> Submit </button> 
0
source

All Articles