Validação dinâmica e nome em um formulário com o AngularJS

Eu tenho este formulário: http://jsfiddle.net/dfJeN/

Como você pode ver, o valor do nome da input é definido estaticamente:

name="username" 

, a validação de formulário funciona bem (adicione algo e remova todo o texto da input, um texto deve aparecer).

Então eu tento definir dinamicamente o valor do nome: http://jsfiddle.net/jNWB8/

 name="{input.name}" 

Então eu aplico isso à minha validação

 login.{{input.name}}.$error.required 

(esse padrão será usado em um ng-repeat), mas a validação do meu formulário está quebrada. É interpretado corretamente no meu navegador (se eu inspecionar o elemento, eu vi login.username. $ Error.required).

Qualquer ideia ?

EDIT: Depois de registrar o escopo no console, parece que o

 {{input.name}} 

a expressão não é interpolada. Minha forma como um atributo {{input.name}}, mas sem nome de usuário.

UPDATE: Desde 1.3.0-rc.3 name = “{{input.name}}” funciona como esperado. Por favor, veja # 1404

Você não pode fazer o que está tentando fazer dessa maneira.

Supondo o que você está tentando fazer é que você precisa adicionar dinamicamente elementos a um formulário, com algo como um ng-repeat, você precisa usar o ng-form nested para permitir a validação desses itens individuais:

 
required

Infelizmente, não é apenas uma característica bem documentada do Angular.

O uso do ngForm nested permite acessar o InputController específico a partir do modelo HTML. No entanto, se você deseja acessá-lo de outro controlador, isso não ajuda.

por exemplo

   

Eu uso essa diretiva para ajudar a resolver o problema:

 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); } }; }); 

Agora você usa nomes dynamics onde é necessário apenas o atributo ‘dynamic-name’ em vez do atributo ‘name’.

por exemplo

   

O problema deve ser corrigido no AngularJS 1.3, de acordo com essa discussão no Github .

Enquanto isso, aqui está uma solução temporária criada por @caitp e @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; }); }]); 

Demonstração no JSFiddle .

Nice por @EnISeeK …. mas eu tenho que ser mais elegante e menos intrusivo a outras directivas:

 .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]); } }; }]) 

Apenas um pouco de melhoria sobre a solução da 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); }] }; }]); 

Aqui está um julgamento plunker . Aqui está uma explicação detalhada

Eu amplio um pouco a solução @caitp e @Thinkscape, para permitir que ng-forms nesteds criados dinamicamente, assim:

 
Dirty:
Dirty:

Aqui está minha demonstração no JSFiddle .

Eu usei a solução de Ben Lesh e funciona bem para mim. Mas um problema que enfrentei foi que quando adicionei uma forma interna usando ng-form , todos os estados de formulário, por exemplo, form.$valid, form.$error etc ficaram indefinidos se eu estivesse usando a diretiva ng-submit .

Então, se eu tivesse isso, por exemplo:

 

E no meu controlador:

 $scope.saveRecord = function() { outerForm.$valid // this is undefined } 

Então, tive que voltar a usar um evento de clique regular para enviar o formulário. Nesse caso, é necessário passar o object de formulário:

 

E o método revisado do controlador:

 $scope.saveRecord = function(outerForm) { outerForm.$valid // this works } 

Eu não tenho certeza porque isso é, mas espero que ajude alguém.

Este problema foi corrigido no Angular 1.3+ Esta é a syntax correta para o que você está tentando fazer:

 login[input.name].$invalid