Passar forma para diretiva

Eu quero encapsular meus campos de formulário em uma diretiva para que eu possa simplesmente fazer isso:

Como eu access o myForm na minha diretiva para que eu possa fazer verificações de validação, por exemplo, myForm.Email.$valid ?

Para acessar o FormController em uma diretiva:

 require: '^form', 

Em seguida, ele estará disponível como o quarto argumento para sua function de link:

 link: function(scope, element, attrs, formCtrl) { console.log(formCtrl); } 

violino

Você só precisa acessar o NgModelController embora:

 require: 'ngModel', link: function(scope, element, attrs, ngModelCtrl) { console.log(ngModelCtrl); } 

violino

Se você precisar de access a ambos:

 require: ['^form','ngModel'], link: function(scope, element, attrs, ctrls) { console.log(ctrls); } 

violino

Aqui está um exemplo completo: http://plnkr.co/edit/W1KxuL?p=preview (estilizado usando o Bootstrap 3.1)

Contém um formulário com várias inputs (nome, email, idade e país). Nome, email e idade são diretivas. O país é uma input “regular”.

Para cada input é exibida uma mensagem de ajuda quando o usuário não insere um valor correto.

O formulário contém um botão de salvaguarda que está desativado se o formulário contiver pelo menos um erro.

       
Person:
{{person | json}}

Form $error:

{{myForm.$error | json}}

Is the form valid?: {{myForm.$valid}}

Is name valid?: {{myForm.name.$valid}}

// inputName.js app.directive('inputName', function() { return { restrict: 'E', templateUrl: 'input-name.html', replace: false, controller: 'InputNameCtrl', require: ['^form', 'ngModel'], // See Isolating the Scope of a Directive http://docs.angularjs.org/guide/directive#isolating-the-scope-of-a-directive scope: {}, link: function(scope, element, attrs, ctrls) { scope.form = ctrls[0]; var ngModel = ctrls[1]; if (attrs.required !== undefined) { // If attribute required exists // ng-required takes a boolean scope.required = true; } scope.$watch('name', function() { ngModel.$setViewValue(scope.name); }); } }; }); // inputNameCtrl app.controller('InputNameCtrl', ['$scope', function($scope) { }]);

Formulário AngularJS com diretivas

Edit 2: Vou deixar minha resposta, pois pode ser útil por outras razões, mas a outra resposta de Mark Rajcok é o que eu originalmente queria fazer, mas não consegui chegar ao trabalho. Aparentemente, o controlador pai aqui seria form , não ngForm .


Você pode passá-lo usando um atributo em sua diretiva, embora isso seja bastante detalhado.

Exemplo

Aqui está um jsFiddle funcional e simplificado .

Código

HTML:

 

Partes essenciais da directiva:

 app.directive('myInput', function() { return { scope: { form: '=' }, link: function(scope, element, attrs) { console.log(scope.form); } }; }); 

O que está acontecendo

Solicitamos ao Angular que vincule o valor do escopo denominado no atributo form ao nosso escopo isolado, usando um '=' .

Fazê-lo desta maneira dissocia o formulário atual da diretiva de input.

Nota: Eu tentei usar require: "^ngForm" , mas a diretiva ngForm não define um controlador e não pode ser usada dessa maneira (o que é muito ruim).


Tudo o que foi dito, eu acho que esta é uma maneira muito detalhada e confusa para lidar com isso. Talvez seja melhor adicionar uma nova diretiva ao elemento form e usar require para acessar esse item. Vou ver se consigo juntar alguma coisa.

Editar: usando uma diretiva pai

OK, aqui está o melhor que consegui descobrir usando uma diretiva pai, explicarei mais em um segundo:

Trabalhando jsFiddle usando diretiva pai

HTML:

 

JS (parcial):

 app.directive('myForm', function() { return { restrict: 'E', scope: { form: '=' }, controller: ['$scope', function($scope) { this.getForm = function() { return $scope.form; } }] } }); app.directive('myInput', function() { return { require: '^myForm', link: function(scope, element, attrs, myForm) { console.log(myForm.getForm()); } }; }); 

Isso armazena o formulário no escopo da diretiva pai ( myForm ) e permite que as diretivas filho acessem-no, exigindo o formulário pai ( require: '^myForm' ) e acessando o controlador da diretiva na function de vinculação ( myForm.getForm() ) .

Benefícios:

  • Você só precisa identificar o formulário em um só lugar
  • Você pode usar seu controlador pai para abrigar o código comum

Negativos:

  • Você precisa de um nó extra
  • Você precisa colocar o nome do formulário duas vezes

O que eu prefiro

Eu estava tentando fazê-lo funcionar usando um atributo no elemento de formulário . Se isso funcionasse, você só teria que adicionar a diretiva ao mesmo elemento que ngForm .

No entanto, eu estava recebendo algum comportamento estranho com o escopo, onde a variável myFormName seria visível dentro do $scope , mas seria undefined quando eu tentasse acessá-lo. Aquele me confundiu.

Começando com o AngularJS 1.5.0, há uma solução muito mais limpa para isso (em oposição ao uso direto da function de link ). Se você quiser acessar o FormController um formulário no controlador de diretivas do seu subcomponente, você pode simplesmente dar um tapa no atributo require na diretiva, da seguinte forma:

 return { restrict : 'EA', require : { form : '^' }, controller : MyDirectiveController, controllerAs : 'vm', bindToController : true, ... }; 

Em seguida, você poderá acessá-lo em seu modelo ou controlador de diretriz como faria com qualquer outra variável de escopo, por exemplo :

 function MyDirectiveController() { var vm = this; console.log('Is the form valid? - %s', vm.form.$valid); } 

Observe que para isso funcionar, você também precisa ter o atributo bindToController: true configurado em sua diretiva. Veja a documentação para $compile e esta questão para mais informações.

Partes relevantes da documentação:

exigir

Exigir outra diretiva e injetar seu controlador como o quarto argumento para a function de vinculação. A propriedade require pode ser uma string , uma matriz ou um object :

Se a propriedade require for um object e bindToController for bindToController , os controladores necessários serão ligados ao controlador usando as chaves da propriedade require. Se o nome do controlador requerido é o mesmo que o nome local (a chave), o nome pode ser omitido. Por exemplo, {parentDir: '^parentDir'} é equivalente a {parentDir: '^'} .

Fez o seu trabalho “O que eu prefiro” violino! Por algum motivo, você pode ver a string “$ scope.ngForm” em um console.log, mas registrá-la diretamente não funcionou, resultando em indefinida. No entanto, você pode obtê-lo se passar atributos para a function do controlador.

 app.directive('myForm', function() { return { restrict: 'A', controller: ['$scope','$element','$attrs', function($scope,$element,$attrs) { this.getForm = function() { return $scope[$attrs['ngForm']]; } }] } }); 

http://jsfiddle.net/vZ6MD/20/