AngularJS: Fields added dynamically are not registered on FormController
Solution 1
Update 7/31/2015 This has been fixed since 1.3, see here: https://github.com/angular/angular.js/issues/1404#issuecomment-125805732
Original Answer This is unfortunately a short coming of AngularJS at the moment. Angular's form validation doesn't work with dynamically named fields. You can add the following at the bottom of your HTML to see exactly what's going on:
<pre>{{myForm|json}}</pre>
As you can see, Angular isn't getting the dynamic input name right. There's currently a work around involving nested forms that can get kind of nasty, but it does work and (with a little extra work) will submit the parent form without trouble.
If you want, you can go drum up more support for the issue: GitHub Issue - dynamic element validation. Either way, here's the code:
http://jsfiddle.net/langdonx/6H8Xx/2/
HTML:
<div data-ng-app>
<div data-ng-controller="MyController">
<form id="my_form" name="my_form" action="/echo/jsonp/" method="get">
<div data-ng-repeat="field in form.data.fields">
<ng-form name="form">
<label for="{{ field.name }}">{{ field.label }}:</label>
<input type="text" id="{{ field.name }}" name="{{field.name}}" data-ng-model="field.data" required>
<div class="validation_error" data-ng-show="form['\{\{field.name\}\}'].$error.required">Can't be empty.</div>
</ng-form>
</div>
<input type="submit" />
</form>
</div>
</div>
JavaScript:
MyController.$inject = ["$scope"];
function MyController($scope) {
$scope.form = {};
$scope.form.data = {};
$scope.form.data.fields = []
var f1 = {
"name": "input_1",
"label": "My Label 1",
"data": ""
};
var f2 = {
"name": "input_2",
"label": "My Label 2",
"data": ""
};
$scope.form.data.fields.push(f1);
$scope.form.data.fields.push(f2);
}
Solution 2
I ran into a similar problem myself and what i did to work around it was to place the name of the field before calling $compile on the template. A simple string.replace did the trick. Then again that was only possible because i was getting the field templates in through http and had access to the template text.
update: here is a fiddle with a little hack to make your example work
app.directive('field', function($compile) {
var linker= function(scope, element){
var template = '<input type="text" name="{{fname}}" ng-model="model">'
.replace('{{fname}}', scope.fname);
element.html(template)
$compile(element.contents())(scope)
}
return {
restrict: 'E',
scope: {
fname: '=',
model: '='
},
replace: true,
link: linker
};
});
http://jsfiddle.net/2Ljgfsg9/4/
AngularChef
Formations et tutos Angular en français - https://www.angularchef.com/
Updated on June 07, 2022Comments
-
AngularChef about 2 years
I have the following static form in AngularJS:
<form name="myForm" class="form-horizontal"> <label>First Name:</label> <input type="text" name="first_name" ng-model="entity.first_name"> <label>Last Name:</label> <input type="text" name="last_name" ng-model="entity.last_name"> </form>
Angular creates a FormController for me and publishes it into the scope (under the form name). Which means I have access to properties like the following:
$scope.myForm.first_name.$error $scope.myForm.last_name.$invalid ...
This is super useful!
But in my case I'm building a form dynamically, using directives:
<form name="myForm" class="form-horizontal"> <field which="first_name"></field> <field which="last_name"></field> </form>
The
<field>
directives don't resolve to actual<input>
elements until after a while (after I've fetched some data from the server, linked the directives, etc.).The problem here is that no field properties are defined on the form controller, as if dynamic fields didn't register with the FormController:
// The following properties are UNDEFINED (but $scope.myForm exists) $scope.myForm.first_name $scope.myForm.last_name
Any idea why? Any solution/workaround?
You can see the entire code in this jsFiddle:
http://jsfiddle.net/vincedo/3wcYV/