I have a form with some text input fields and a dynamic list of items stored in the $scope of the controller, with some functions to add/remove items in the list. I want to invalidate the form until the items list reaches a predefined length.
我有一个表单,其中包含一些文本输入字段和存储在控制器的$ scope中的动态项目列表,其中一些函数用于添加/删除列表中的项目。我想使表单无效,直到项目列表达到预定义的长度。
So I created a formRepeat directive which takes a ngModel attribute and then use the ngModelController to invalidate the form.
所以我创建了一个formRepeat指令,该指令接受ngModel属性,然后使用ngModelController使表单无效。
http://plnkr.co/edit/jSFvak?p=preview
This works but I think it's not the better way to do that as the directive is not very flexible.
这有效,但我认为这不是更好的方法,因为指令不是很灵活。
The easiest would be to invalidate the form in the controller with something like :
最简单的方法是使控制器中的表单无效:
$scope.myForm.$valid = false;
But this doesn't work.
但这不起作用。
Is there a better way ?
有没有更好的办法 ?
7 个解决方案
#1
3
Based upon your plunker. I'd use the following $watch
function (similar to @NicolasMoise response)
基于你的plunker。我使用以下$ watch函数(类似于@NicolasMoise响应)
$scope.$watch('items', function (items) {
$scope.myForm.$setValidity('count', items.length >= 5);
}, true);
It's important to set the objectEquality
flag to true
so that the $watch
will fire if any of the objects properties change
将objectEquality标志设置为true非常重要,这样如果任何对象属性发生更改,$ watch将会触发
or, if only a shallow list (collection) comparison is made, use $watchCollection
或者,如果只进行浅层列表(集合)比较,请使用$ watchCollection
$scope.$watchCollection('items', function (items) {
$scope.myForm.$setValidity('count', items.length >= 5);
});
I've also never had any luck with $setValidity('$valid')
or similar
我也没有运气$ setValidity('$ valid')或类似的
#2
7
The easiest way for me was to target array's length as hidden number input
and put min
validation on it. Very clean solution, in fact.
对我来说最简单的方法是将数组的长度作为隐藏数字输入,并对其进行最小化验证。事实上,非常干净的解决方案。
<input style="display: none;" type="number" name="itemsCount" ng-model="items.length" min="{{min}}">
Check out the updated plunker
查看更新的plunker
#3
3
The best way to do so (IMO) is to create a custom directive that uses the ngModelController Validators.
这样做的最佳方法(IMO)是创建一个使用ngModelController验证器的自定义指令。
Validators get executed every time there is an update on the model and are used for form validity. Your directive may 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 can call it from your HTML like this:
并且可以从您的HTML中调用它,如下所示:
<input type="text" name="content" ng-list min-length="2" ng-model="content" />
You can find the working example on the following Plunker.
您可以在以下Plunker上找到工作示例。
#4
1
I don't think it's necessary to use a directive in this case. Just have an ng-repeat for items and inside your controller something like this
在这种情况下,我认为没有必要使用指令。只需对项目进行ng-repeat,并在控制器内部进行类似的操作
$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...)
}
})
#5
0
maybe it is what your looking for http://docs.angularjs.org/api/ng/type/form.FormController
也许这就是你在寻找http://docs.angularjs.org/api/ng/type/form.FormController
#6
0
I think you can achieve this using ng-class.
我认为你可以使用ng-class实现这一目标。
Try this , In HTML,
试试这个,在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 your script.js,
在你的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,
在css文件中,
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 this?.
你想要这样的东西吗?
Please have a look at this plunker
请看看这个plunker
#7
0
a bit late, but I do that like this:
有点晚了,但我这样做:
<button type="button" class="btn btn-success"
ng-disabled="form.$invalid || user.groups.length == 0>
Submit
</button>
#1
3
Based upon your plunker. I'd use the following $watch
function (similar to @NicolasMoise response)
基于你的plunker。我使用以下$ watch函数(类似于@NicolasMoise响应)
$scope.$watch('items', function (items) {
$scope.myForm.$setValidity('count', items.length >= 5);
}, true);
It's important to set the objectEquality
flag to true
so that the $watch
will fire if any of the objects properties change
将objectEquality标志设置为true非常重要,这样如果任何对象属性发生更改,$ watch将会触发
or, if only a shallow list (collection) comparison is made, use $watchCollection
或者,如果只进行浅层列表(集合)比较,请使用$ watchCollection
$scope.$watchCollection('items', function (items) {
$scope.myForm.$setValidity('count', items.length >= 5);
});
I've also never had any luck with $setValidity('$valid')
or similar
我也没有运气$ setValidity('$ valid')或类似的
#2
7
The easiest way for me was to target array's length as hidden number input
and put min
validation on it. Very clean solution, in fact.
对我来说最简单的方法是将数组的长度作为隐藏数字输入,并对其进行最小化验证。事实上,非常干净的解决方案。
<input style="display: none;" type="number" name="itemsCount" ng-model="items.length" min="{{min}}">
Check out the updated plunker
查看更新的plunker
#3
3
The best way to do so (IMO) is to create a custom directive that uses the ngModelController Validators.
这样做的最佳方法(IMO)是创建一个使用ngModelController验证器的自定义指令。
Validators get executed every time there is an update on the model and are used for form validity. Your directive may 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 can call it from your HTML like this:
并且可以从您的HTML中调用它,如下所示:
<input type="text" name="content" ng-list min-length="2" ng-model="content" />
You can find the working example on the following Plunker.
您可以在以下Plunker上找到工作示例。
#4
1
I don't think it's necessary to use a directive in this case. Just have an ng-repeat for items and inside your controller something like this
在这种情况下,我认为没有必要使用指令。只需对项目进行ng-repeat,并在控制器内部进行类似的操作
$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...)
}
})
#5
0
maybe it is what your looking for http://docs.angularjs.org/api/ng/type/form.FormController
也许这就是你在寻找http://docs.angularjs.org/api/ng/type/form.FormController
#6
0
I think you can achieve this using ng-class.
我认为你可以使用ng-class实现这一目标。
Try this , In HTML,
试试这个,在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 your script.js,
在你的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,
在css文件中,
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 this?.
你想要这样的东西吗?
Please have a look at this plunker
请看看这个plunker
#7
0
a bit late, but I do that like this:
有点晚了,但我这样做:
<button type="button" class="btn btn-success"
ng-disabled="form.$invalid || user.groups.length == 0>
Submit
</button>