dynamicvalidation和与AngularJSforms的名称
我有这种forms: http : //jsfiddle.net/dfJeN/
正如你所看到的,input的名字值是静态设置的:
name="username"
,表单validation工作正常(添加一些东西,并从input中删除所有文本,一个文本必须出现)。
然后我尝试dynamic设置名称值: http : //jsfiddle.net/jNWB8/
name="{input.name}"
然后我将这个应用到我的validation
login.{{input.name}}.$error.required
(这个模式将用于ng-repeat),但我的表单validation被打破。 它在我的浏览器中正确解释(如果我检查元素,我看到login.username。$ error.required)。
任何想法 ?
编辑:在控制台中logging范围后,它出现了
{{input.name}}
expression式不是插值的。 我的表单是{{input.name}}属性,但没有用户名。
更新:由于1.3.0-rc.3 name =“{{input.name}}”按预期工作。 请参阅#1404
你不能做你想要这样做的事情。
假设你想要做的是你需要dynamic地添加元素到一个表单,像ng重复,你需要使用嵌套的ng表单来validation这些单独的项目:
<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的一个很好的loggingfunction。
使用嵌套的ngForm允许您从HTML模板中访问特定的InputController。 但是,如果您希望从另一个控制器访问它,则无济于事。
例如
<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名称”属性而不是“名称”属性,就可以使用dynamic名称。
例如
<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>
根据对Github的讨论,这个问题应该在AngularJS 1.3中解决。
同时,这是@caitp和@Thinkscape创build的临时解决scheme:
// 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上演示。
@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]); } }; }])
只比EnlSeek解决scheme稍微改进一点
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); }] }; }]);
这是一个暴徒试验 。 这里是详细的解释
我扩展了@caitp和@Thinkscape解决scheme,允许dynamic创build嵌套的ng表单 ,如下所示:
<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上的演示。
我用Ben Lesh的解决scheme,对我来说效果很好。 但是我遇到的一个问题是,当我使用ng-form
添加一个内部表单时,如果我正在使用ng-submit
指令,那么所有的表单状态,例如form.$valid, form.$error
。
所以如果我有这个例子:
<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 }
我不太确定这是为什么,但希望它可以帮助别人。
这个问题已经在Angular 1.3+中修复了这是你正在尝试做的正确的语法:
login[input.name].$invalid