I'm creating inputs inside a form dynamically. I created this directive for the purpose:
// Generate inputs on the fly using BE data.
.directive('inputGenerator', ['$compile', function ($compile) {
return {
restrict: 'E',
scope: {
id: '@',
type: '@',
name: '@',
attributes: '=',
ngModel: '=',
ngDisabled: '='
},
link: function (scope, iElement, iAttrs) {
// Get attributes
var id = iAttrs.id,
type = iAttrs.type,
name = iAttrs.name;
scope.ngModel[name] = {};
var extended_attributes = {
"type": type,
"id": id,
"data-ng-model": 'ngModel.' + name + '[\'value\']',
"name": name,
"data-ng-disabled": "ngDisabled"
};
if ( ! scope.attributes) {
scope.attributes = {};
}
// Append extra attributes to the object
angular.extend(scope.attributes, extended_attributes);
// Generate input
var input = '<input ';
angular.forEach(scope.attributes, function (value, key) {
input += key + '="' + value + '" ';
});
input += '/>';
// Compile input element using current scope (directive) variables
var compiledElement = $compile(input)(scope);
// Set the file selected name as the model value
compiledElement.on('change', function () {
if (this.files && this.files[0].name) {
var that = this;
scope.$apply(function () {
scope.ngModel[name] = {};
scope.ngModel[name]['value'] = that.files[0].name;
});
}
});
// Replace directive element with generated input
iElement.replaceWith(compiledElement);
}
};
}]);
This html line will trigger the directive:
<input-generator data-name="{{ item.name }}" data-ng-model="inputs.sources" data-attributes="item.attrs" data-type="{{ item.type }}" data-id="inputFile_{{ $index }}" data-ng-disabled="inputs.sources[item.name].selected" />
I'm running on Angular 1.4.3.
Problem
The model and pretty much everything works fine in the directive, but for some reason the form remains valid when the input added is invalid as you can see in this image.
I already tried:
Any of the Angular features of form validation works
I debugged Angular and seems to be that the input attached to the form is different from the input compiled inside the directive.
I already called formName.$setPristine()
after each input was created, but it didn't work.
I couldn't access the form from the directive, but I think is not a good idea either.
I already wrapped the input with a ng-form tag, but nothing useful comes out of that.
I tried to use the directive compile method, but this is just triggered once when the app loads and I've a select input that loads different inputs on change.
Any help on this is much appreciated! :)
Thank you to everyone for contribute anyways!!
I ran into this issue as well with Angular v1.5.9. The main issue here is that you are compiling the HTML template before it is in the DOM, so Angular doesn't know it's part of the form. If you add the HTML first, then compile, Angular will see your input as a form child, and it will be used in the form validation.
See similar answer to Form Validation and fields added with $compile
Don't do:
Do this instead:
Note: I swapped the more conventional
element
for OP'siElement
, which is a jQLite reference of the directive's HTML elementyou need to use ng-form directive as a wrapper for your input.
you can see an example of this here
but it works for me. You can pass the form reference to the directive and use it directly.
in the code below, the scope.form is used to know the general state of the form, and the scope.name to access the input field state.
< ng-form name="{{name}}" ng-class="{error: this[name][name].$invalid && form.$submitted}" >
i hope it helps
You should definitely take a look at my Angular-Validation Directive/Service. It as a ton of features and I also support dynamic inputs validation, you can also pass an isolated scope which helps if you want to not only have dynamic inputs but also have dynamic forms, also good to use inside a modal window.
For example, let's take this example being a dynamic form and inputs defined in the Controller:
It will bind the validation to the elements and if you want to easily check for the form validity directly from the Controller, simply use this
You can also use interpolation like so
Or using a radio/checkbox to enable/disable a field that you still want to validate when it becomes enable:
It really as a lot of features, and is available on both
Bower
andNuGet
(under the tag name ofangular-validation-ghiscoding
). So please take a look at my library Angular-Validation and a live demo on PLUNKER.It's loaded with features (custom Regex validators, AJAX remote validation, validation summary, alternate text errors, validation on the fly with the Service, etc...). So make sure to check the Wiki Documentation as well... and finally, it's fully tested with Protractor (over 1500 assertions), so don't be afraid of using in production.
Please note that I am the author of this library
you need to set name of control dynamic and use this dynamic name for form validation. in the following e.g. you see the dynamic name and id of control and used for the validation of angular (using ng-massages) more details see http://www.advancesharp.com/blog/1208/dynamic-angular-forms-validation-in-ngrepeat-with-ngmessage-and-live-demo
Field Num Is Required.