AngularJS form hardening for dynamically generated input directives not working with ngForm
I am trying to validate dynamic form input created using directive and isolate scopes. Outside of the directive, I have a main form, and inside the ng-repeat, I try to use ng-form, but it never displays error messages. I originally had an ng form on ng-repeat, but figured it wouldn’t work as it is not in scope in the directive, so I put it in the parent div of the directive, but still doesn’t show validation for invalid email ...
Form with ng-repeat and field directive
<form name="mainForm"
role="form"
ng-controller="WizardFormController as wizFormCtrl"
ng-submit="submit( mainForm.$valid )"
novalidate>
<div ng-repeat="field in panel.form_fields">
<form-field field="field"
model="models[field.field_name]" ng-form="subForm">
</form-field>
</div>
<div class="form-group clearfix">
<button class="btn btn-primary pull-right"
ng-click="update( models )"
ng-disabled="mainForm.$invalid">Save Progress</button>
</div>
</form>
Form field directive
<div class="form-group" ng-form="subForm">
<label for="{{field.field_name}}">{{field.field_label}}</label>
<input type="text"
class="form-control"
id="{{field.field_id}}"
name="{{field.field_name}}"
ng-model="model">
<div ng-show="subForm[field.field_name].$dirty &&
subForm[field.field_name].$invalid">Invalid:
<span ng-show="subForm[field.field_name].$error.email">This is not a valid email.</span>
</div>
</div>
It looks like it should work by looking at the generated markup indicating that the field is ng-valid:
<div class="form-group ng-scope ng-dirty ng-valid-required ng-valid ng-valid-email"
ng-form="subForm">
I just access the subForm:
subForm[field.field_name].$dirty
UPDATE I found work for this and answered below, see here
source to share
The solution to this problem seems to work and has been a problem for 2+ years now. Add your voice to it on GitHub ! The easiest solution to implement and perhaps the best solution can be found here with Thinkscape in mind and I copied it below.
angular.module('interpol', [])
.config(function($provide) {
$provide.decorator('ngModelDirective', function($delegate) {
var ngModel = $delegate[0], controller = ngModel.controller;
ngModel.controller = ['$scope', '$element', '$attrs', '$injector', function(scope, element, attrs, $injector) {
var $interpolate = $injector.get('$interpolate');
attrs.$set('name', $interpolate(attrs.name || '')(scope));
$injector.invoke(controller, this, {
'$scope': scope,
'$element': element,
'$attrs': attrs
});
}];
return $delegate;
});
$provide.decorator('formDirective', function($delegate) {
var form = $delegate[0], controller = form.controller;
form.controller = ['$scope', '$element', '$attrs', '$injector', function(scope, element, attrs, $injector) {
var $interpolate = $injector.get('$interpolate');
attrs.$set('name', $interpolate(attrs.name || attrs.ngForm || '')(scope));
$injector.invoke(controller, this, {
'$scope': scope,
'$element': element,
'$attrs': attrs
});
}];
return $delegate;
});
})
.run(function($rootScope) {
$rootScope.models = [{
value: 'foo'
},{
value: 'bar'
},{
value: 'baz'
}];
});
I just ran it, marking it as a dependency and the form in my question works.
Greetings
source to share
use this as a form field directive:
<div class="form-group" ng-form="subForm">
<label for="{{field.field_name}}">{{field.field_label}}</label>
<input type="email"
class="form-control"
id="formid"
name="formname"
ng-model="model">
<div ng-show="subForm.formname.$dirty &&
subForm.formname.$invalid">Invalid:
<span ng-show="subForm.formname.$error.email">This is not a valid email.</span>
</div>
</div>
ng-form handles the field name on its own. you cannot deliver name="{{field.field_name}}"
like this.
source to share