Форма перехода к директиве
Я хочу инкапсулировать поля формы в директиве, чтобы я мог просто сделать это:
<div ng-form='myForm'>
<my-input name='Email' type='email' label='Email Address' placeholder="Enter email" ng-model='model.email' required='false'></my-input>
</div>
Как мне получить доступ к myForm
в моей директиве, чтобы я мог выполнять проверки проверки, например. myForm.Email.$valid
?
Ответы
Ответ 1
Чтобы получить доступ к FormController в директиве:
require: '^form',
Затем он будет доступен в качестве 4-го аргумента для вашей функции ссылок:
link: function(scope, element, attrs, formCtrl) {
console.log(formCtrl);
}
fiddle
Вам может потребоваться доступ только к NgModelController:
require: 'ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
console.log(ngModelCtrl);
}
fiddle
Если вам нужен доступ к обоим:
require: ['^form','ngModel'],
link: function(scope, element, attrs, ctrls) {
console.log(ctrls);
}
fiddle
Ответ 2
Вот полный пример: http://plnkr.co/edit/W1KxuL?p=preview (с использованием Bootstrap 3.1)
Он содержит форму с несколькими входами (имя, адрес электронной почты, возраст и страну).
Имя, адрес электронной почты и возраст - это директивы. Страна - это "обычный" вход.
Для каждого ввода отображается справочное сообщение, когда пользователь не вводит правильное значение.
Форма содержит кнопку сохранения, которая отключена, если форма содержит хотя бы одну ошибку.
![AngularJS form with directives]()
Ответ 3
Изменить 2: Я оставлю свой ответ, поскольку это может быть полезно по другим причинам, но другой ответ от Марка Райкока - это то, что я изначально хотел сделать, но не смог работать, По-видимому, родительский контроллер здесь был бы form
, а не ngForm
.
Вы можете передать его с помощью атрибута в своей директиве, хотя это будет довольно подробным.
Пример
Здесь работает, упрощенный jsFiddle.
Код
HTML:
<div ng-form="myForm">
<my-input form="myForm"></my-input>
</div>
Основные части директивы:
app.directive('myInput', function() {
return {
scope: {
form: '='
},
link: function(scope, element, attrs) {
console.log(scope.form);
}
};
});
Что происходит
Мы попросили Angular связать значение области, названное в атрибуте form
, с нашей изолированной областью, используя '='
.
Выполнение этого способа отделяет фактическую форму от директивы ввода.
Примечание.. Я попытался использовать require: "^ngForm"
, но директива ngForm не определяет контроллер и не может использоваться таким образом (что очень плохо).
Все сказанное, я думаю, что это очень многословный и грязный способ справиться с этим. Возможно, вам лучше добавить новую директиву в элемент формы и использовать require
для доступа к этому элементу. Я посмотрю, смогу ли я что-то собрать вместе.
Изменить: использование родительской директивы
ОК, здесь лучшее, что я мог бы выяснить, используя родительскую директиву, я объясню больше через секунду:
Работа jsFiddle с помощью родительской директивы
HTML:
<div ng-app="myApp">
<div ng-form="theForm">
<my-form form="theForm">
<my-input></my-input>
</my-form>
</div>
</div>
JS (частичный):
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());
}
};
});
Сохраняет форму в области родительской директивы (myForm
) и позволяет дочерним директивам обращаться к ней, требуя родительскую форму (require: '^myForm'
), и доступ к контроллеру директивы в функции связывания (myForm.getForm()
).
Преимущества:
- Вам нужно только идентифицировать форму в одном месте.
- Вы можете использовать свой родительский контроллер для размещения общего кода
Отрицательных:
- Вам нужен дополнительный node
- Вам нужно дважды ввести имя формы
Что бы я предпочел
Я пытался заставить его работать с помощью атрибута в элементе формы. Если это сработало, вам нужно будет добавить директиву к тому же элементу, что и ngForm
.
Однако я получал какое-то странное поведение с областью действия, где переменная myFormName
была бы видна внутри $scope
, но была бы undefined
, когда я попытался получить к ней доступ. Это меня смущает.
Ответ 4
Начиная с AngularJS 1.5.0, для этого существует гораздо более чистое решение (в отличие от использования функции link
). Если вы хотите получить доступ к форме FormController
в вашем контроллере директивы подкомпонента, вы можете просто пощекотать атрибут require
в директиве, например:
return {
restrict : 'EA',
require : {
form : '^'
},
controller : MyDirectiveController,
controllerAs : 'vm',
bindToController : true,
...
};
Затем вы сможете получить доступ к нему в своем шаблоне или директивном контроллере, как и любая другая переменная области видимости, например:
function MyDirectiveController() {
var vm = this;
console.log('Is the form valid? - %s', vm.form.$valid);
}
Обратите внимание, что для этого вам также необходимо установить атрибут bindToController: true
в вашей директиве. Дополнительную информацию см. В документации для $compile
и этого вопроса.
Соответствующие части документации:
требуется
Требовать другую директиву и ввести свой контроллер в качестве четвертого аргумента функции связывания. Свойством require может быть строка, массив или объект:
Если свойство require является объектом и bindToController
является правдивым, то необходимые контроллеры привязаны к контроллеру, используя ключи свойства require. Если имя требуемого контроллера совпадает с именем локального (ключ), имя может быть опущено. Например, {parentDir: '^parentDir'}
эквивалентно {parentDir: '^'}
.
Ответ 5
Сделал свою работу "Что бы я предпочел"!
По какой-то причине вы можете увидеть строку "$ scope.ngForm" в console.log, но запись в нее напрямую не сработала, в результате получилось undefined.
Однако вы можете получить его, если передаете атрибуты функции контроллера.
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/