我有这样的表格:http://jsfiddle.net/dfJeN/
正如您所看到的,输入的名称值是静态设置的:
name="username"
,表单验证工作正常(添加内容并从输入中删除所有文本,必须出现文本)。
然后我尝试动态设置名称值:http://jsfiddle.net/jNWB8/
name="{input.name}"
然后我将此应用于我的验证
login.{{input.name}}.$error.required
(此模式将用于ng-repeat)但我的表单验证已被破坏。它在我的浏览器中被正确解释(如果我检查了看到login.username。$ error.required的元素。)
任何想法?
编辑:在控制台中记录范围后,显示
{{input.name}}
表达式不是插值。我的表单为{{input.name}}属性,但没有用户名。
更新:自1.3.0-rc.3 name =“{{input.name}}”按预期工作。请参阅#1404
答案 0 :(得分:175)
你不能做你想做的事情。
假设你要做的是你需要动态地向表单添加元素,使用像ng-repeat这样的东西,你需要使用嵌套的ng-form来验证那些单独的项目:
<form name="outerForm">
<div ng-repeat="item in items">
<ng-form name="innerForm">
<input type="text" name="foo" ng-model="item.foo" />
<span ng-show="innerForm.foo.$error.required">required</span>
</ng-form>
</div>
<input type="submit" ng-disabled="outerForm.$invalid" />
</form>
可悲的是,这只是Angular没有详细记录的功能。
答案 1 :(得分:44)
使用嵌套的ngForm,您可以从HTML模板中访问特定的InputController。但是,如果您希望从另一个控制器访问它,它将无济于事。
e.g。
<script>
function OuterController($scope) {
$scope.inputName = 'dynamicName';
$scope.doStuff = function() {
console.log($scope.formName.dynamicName); // undefined
console.log($scope.formName.staticName); // InputController
}
}
</script>
<div controller='OuterController'>
<form name='myForm'>
<input name='{{ inputName }}' />
<input name='staticName' />
</form>
<a ng-click='doStuff()'>Click</a>
</div>
我使用此指令来帮助解决问题:
angular.module('test').directive('dynamicName', function($compile, $parse) {
return {
restrict: 'A',
terminal: true,
priority: 100000,
link: function(scope, elem) {
var name = $parse(elem.attr('dynamic-name'))(scope);
// $interpolate() will support things like 'skill'+skill.id where parse will not
elem.removeAttr('dynamic-name');
elem.attr('name', name);
$compile(elem)(scope);
}
};
});
现在您只需使用动态名称'dynamic-name'属性而不是'name'属性。
e.g。
<script>
function OuterController($scope) {
$scope.inputName = 'dynamicName';
$scope.doStuff = function() {
console.log($scope.formName.dynamicName); // InputController
console.log($scope.formName.staticName); // InputController
}
}
</script>
<div controller='OuterController'>
<form name='myForm'>
<input dynamic-name='inputName' />
<input name='staticName' />
</form>
<a ng-click='doStuff()'>Click</a>
</div>
答案 2 :(得分:16)
根据Github上的讨论,问题应该在AngularJS 1.3中修复。
同时,这是由@caitp和@Thinkscape创建的临时解决方案:
// Workaround for bug #1404
// https://github.com/angular/angular.js/issues/1404
// Source: http://plnkr.co/edit/hSMzWC?p=preview
app.config(['$provide', 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;
});
}]);
JSFiddle上的演示。
答案 3 :(得分:13)
很好的@EnISeeK ....但我让它更优雅,更不突兀其他指令:
.directive("dynamicName",[function(){
return {
restrict:"A",
require: ['ngModel', '^form'],
link:function(scope,element,attrs,ctrls){
ctrls[0].$name = scope.$eval(attrs.dynamicName) || attrs.dynamicName;
ctrls[1].$addControl(ctrls[0]);
}
};
}])
答案 4 :(得分:7)
与EnlSeek解决方案相比有一点改进
angular.module('test').directive('dynamicName', ["$parse", function($parse) {
return {
restrict: 'A',
priority: 10000,
controller : ["$scope", "$element", "$attrs",
function($scope, $element, $attrs){
var name = $parse($attrs.dynamicName)($scope);
delete($attrs['dynamicName']);
$element.removeAttr('data-dynamic-name');
$element.removeAttr('dynamic-name');
$attrs.$set("name", name);
}]
};
}]);
答案 5 :(得分:5)
我稍微扩展了@caitp和@Thinkscape解决方案,以允许动态创建嵌套ng-forms,如下所示:
<div ng-controller="ctrl">
<ng-form name="form">
<input type="text" ng-model="static" name="static"/>
<div ng-repeat="df in dynamicForms">
<ng-form name="form{{df.id}}">
<input type="text" ng-model="df.sub" name="sub"/>
<div>Dirty: <span ng-bind="form{{df.id}}.$dirty"></span></div>
</ng-form>
</div>
<div><button ng-click="consoleLog()">Console Log</button></div>
<div>Dirty: <span ng-bind="form.$dirty"></span></div>
</ng-form>
</div>
以下是JSFiddle上的演示。
答案 6 :(得分:4)
我使用了Ben Lesh的解决方案,它对我很有用。但我面临的一个问题是,当我使用ng-form
添加内部表单时,所有表单状态,例如如果我使用form.$valid, form.$error
指令,则ng-submit
等未定义。
所以,如果我有这个例子:
<form novalidate ng-submit="saveRecord()" name="outerForm">
<!--parts of the outer form-->
<ng-form name="inner-form">
<input name="someInput">
</ng-form>
<button type="submit">Submit</button>
</form>
在我的控制器中:
$scope.saveRecord = function() {
outerForm.$valid // this is undefined
}
所以我不得不回到使用常规点击事件来提交表单,在这种情况下需要传递表单对象:
<form novalidate name="outerForm"> <!--remove the ng-submit directive-->
<!--parts of the outer form-->
<ng-form name="inner-form">
<input name="someInput">
</ng-form>
<button type="submit" ng-click="saveRecord(outerForm)">Submit</button>
</form>
修改后的控制器方法:
$scope.saveRecord = function(outerForm) {
outerForm.$valid // this works
}
我不太清楚为什么会这样,但希望它有助于某人。
答案 7 :(得分:1)
此问题已在Angular 1.3+中修复 这是您尝试执行的操作的正确语法:
login[input.name].$invalid
答案 8 :(得分:0)
如果我们为如下所示的输入设置动态名称
List<dynamic>
然后,我们将设置验证用于动态名称,如以下代码所示。
<input name="{{dynamicInputName}}" />