I am using ng-form as a parent form and child mg-forms for validation with ng-repeat.
<div ng-form="form">
<div ng-repeat="field in fields">
<div ng-form="subform"><input...></div>
</div>
</div>
And validating like this:
if ($scope.form.subform.$invalid && !$scope.form.subform.$error.required) {
// Do something...
}
(this is very simplified example, I have more different subforms for different input types and with different names, e.g. input[text] is named as a TextForm, input[numeric] is NumericForm etc.)
Everything works as expected if there is only on field. But if ng-repeat generates multiple fields, validation triggers only the last subform, others gets ignored.
Is there a way of cycling through all subforms to check if one of them is invalid?
Also, I am marking all unfilled required fields like this:
if ($scope.form.$error.required) {
angular.forEach($scope.form.$error.required,
function (object, index) {
$scope.form.$error.required[index].$setDirty();
}
);
}
So if my fields are done like this:
....ng-form="TextForm" ng-class="{ 'has-error': TextForm.$dirty && TextForm.$invalid }"....
And it marks all the subforms even if there are many of the same ones with the same name.
Maybe I could do something similar with invalid fields? Though tried many things, nothing worked...
A solution for this is to create a directive that assigns the ngModelController
's error to a variable in each ng-repeat
input.
Below is a possible implementation to get the errors of each subForm. DEMO
JAVASCRIPT (directive)
.directive('ngModelError', function($parse, $timeout) {
return {
require: ['ngModel', 'form'],
link: function(scope, elem, attr, ctrls) {
var ngModel = ctrls[0],
ngForm = ctrls[1],
fieldGet = $parse(attr.ngModelError),
fieldSet = fieldGet.assign,
field = fieldGet(scope);
$timeout(function() {
field.$error = ngModel.$error;
field.ngForm = ngForm;
fieldSet(scope, field);
});
}
};
});
HTML
<form name="form" ng-submit="submit(form, fields)" novalidate>
<div ng-form="subForm" ng-repeat="field in fields"
ng-class="{'has-error': subForm.$invalid && form.$dirty}">
<label class="control-label">{{field.label}}</label>
<input type="{{field.type}}" placeholder="{{field.placeholder}}"
ng-model="field.model" name="field"
ng-required="field.isRequired" class="form-control"
ng-model-error="field" />
</div>
<br>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
JAVASCRIPT (controller)
Please take note how the fields are structure:
.controller('Ctrl', function($scope) {
$scope.fields = {
email: {
type: 'email',
placeholder: 'Enter email',
isRequired: true,
label: 'Email Address'
},
password: {
type: 'password',
placeholder: 'Enter password',
isRequired: true,
label: 'Password'
}
};
$scope.submit = function(form, fields) {
form.$dirty = true;
if(form.$valid) {
// do whatever
} else {
// accessing ngForm for email field
console.log(fields.email.ngForm);
// accessing errors for email field
console.log(fields.email.$error);
// accessing ngForm for password field
console.log(fields.password.ngForm);
// accessing errors for password field
console.log(fields.password.$error);
}
};
})