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) { }]);
![]()
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.
Aqui está um jsFiddle funcional e simplificado .
HTML:
Partes essenciais da directiva:
app.directive('myInput', function() { return { scope: { form: '=' }, link: function(scope, element, attrs) { console.log(scope.form); } }; });
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.
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:
Negativos:
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
forbindToController
, 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']]; } }] } });