Как получить доступ к FormController в родительском контроллере или области действия в AngularJS
У меня есть страница с несколькими формами, и я хочу только показать ее за раз. Для этого я разделил каждую форму на раздел и используя плагин аккордеона Bootstrap, я разрешаю только один открытый раздел за раз.
Моя разметка выглядит примерно так:
<a ng-click="open_section('section1')">Section 1</a>
<div collapse="section1">
<form name="section1Form">
</form>
</div>
<a ng-click="open_section('section2')">Section 2</a>
<div collapse="section2">
<form name="section2Form">
</form>
</div>
Все работает нормально, я могу перемещаться между формами и т.д.
Поскольку я не хочу, чтобы пользователь открывал раздел, если тот, который они в настоящее время редактируют, содержит ошибки проверки, я попытался проверить функцию open_section
, если связанная с ним форма действительна или нет.
Я пробовал, но не мог. Я не смог получить доступ к FormController, связанному с формами в контроллере, который отвечает за страницу. По какой-то причине они не публикуются в рамке.
Это то, что я пробовал:
-
$scope.section1Form
undefined
-
попробовал с $scope.$watch('section1Form, function(){})
, еще undefined
-
попытался добавить имя формы в качестве второго параметра в open_section
следующим образом: open_section('section1', section1Form)
, но в функции второй аргумент undefined
.
Между тегами <form></form>
у меня есть доступ к FormController, но вне их я этого не делаю. Поскольку событие происходит извне <form>
(закрытие, открытие разделов), я не могу передать FormController моему контроллеру, чтобы проверить правильность моих форм.
Есть ли способ обойти это, или мне нужно реорганизовать мою страницу?
Я использую Angular 1.1.5 битв.
Кроме того, проверяя с помощью модуля AngularJS Batarang Chrome, я вижу, что формы публикуются как дочерние области для текущей области.
EDIT: так выглядит иерархия областей для этого приложения.
- root
|
---current controller\ scope
|
----scope that contains the forms
Это потому, что я использую ng-include
? Нет ли способа доступа к этим формам в контроллере?
Ответы
Ответ 1
Чтобы справиться с динамическими формами и, таким образом, динамическим расположением связанного с ним FormController, я использовал простую директиву, чтобы помочь найти область, содержащую форму.
Решение:
Создайте директиву, что $испускает область, связанную с формой:
module.directive('formLocator', function() {
return {
link: function(scope) {
scope.$emit('formLocator');
}
}
Используйте директиву в разметке:
<form name="myForm" novalidate form-locator>
Слушайте трансляцию событий по директиве в контроллере:
$scope.$on('formLocator', function(event) {
$scope.myDeeplyNestedForm = event.targetScope.myForm;
});
Ответ 2
Существует гораздо более простой способ связи с резервной копией в иерархии областей с помощью процесса angular поиска объектов в иерархии областей видимости.
Это позволяет нам присоединить объект из более низкой области видимости к более широкому пространству с помощью точечной нотации.
В этом случае вам нужно создать пустой объект "улавливатель" на контроллере верхнего уровня. Затем этому узловому объекту могут быть назначены объекты формы из нижних областей. Вот демон для демонстрации.
http://plnkr.co/edit/xwsu48bjM3LofAoaRDsN?p=preview
Это не очень элегантно, но если вы думаете об этом объекте "зрелище" в качестве прослушивателя событий, мы по-прежнему следуем стандартным шаблонам.
создать пустой объект-ловушку в контроллере, где вам нужна ссылка на вложенную форму
function mainController($scope){
$scope.catcher = {
};
}
Затем в самой разметке всякий раз, когда объявляется директива ng-form, задайте catcher.formName = formName так
<ng-form name="alpha">
<span ng-init="catcher.alpha = alpha"></span>
<input type="text" required="" ng-model="alphaValue" />
</ng-form>
Поскольку мы назначены "ловушка". angular будет проходить по иерархии областей и найти ее в mainController независимо от любого количества контроллеров между ними (при условии, что у них также нет объекта-уловителя, конечно)
Ответ 3
Поскольку я использовал частичные представления с ng-view
, формы были зарегистрированы в дочерней области моего контроллера. Кажется, что я не могу получить доступ к дочерним областям из родительского, из-за прототипического наследования.
Тем не менее, мне удалось получить экземпляры контроллера формы в моем контроллере, передав их через функцию, которая отвечала за открытие/закрытие аккордеона.
Решение выглядит примерно так:
<a ng-click="open_section('section1', section1Form)">Section 1</a>
<div collapse="section1">
<form name="section1Form">
</form>
</div>
<a ng-click="open_section('section2', section2Form)">Section 2</a>
<div collapse="section2">
<form name="section2Form">
</form>
</div>
Ответ 4
В angular документации можно прочитать:
<form
[name="{string}"]>
</form>
Название формы. Если указано, контроллер формы будет опубликован в соответствующий раздел, под этим именем.
Однако существуют определенные директивы, такие как ngIf, которые создают новую область:
Обратите внимание, что когда элемент удаляется с помощью ngIf его область действия уничтожается и новая область создается при восстановлении элемента.
Это может быть ваш случай? Если это так, вы можете попробовать установить имя формы на что-то вроде "forms.section1Form", а затем соответствующим образом получить доступ к ней в области.
Ответ 5
Чтобы получить доступ к форме из директивы, контроллера и т.д., вы можете использовать ng-init:
Например:
<form name="myForm">
<div ng-init="myLocalScopeVar=form"></div
<input name="myField" ....>
</form>
Вы знаете, что можете получить доступ к данным формы или передать обратно связанную переменную, если это директива. Пример в контроллере для указанного шаблона:
if ($scope.myLocalScopeVar.myField.$valid ) ...
Это похоже на ответ Sinil D отличный ответ, в котором сохраняется форма в родительской области $scope, но она не использует события. Это по сути делает то же самое, но немного меньше накладных расходов.
Ответ 6
Чтобы получить фактическую FormController
, ответственную за определенную директиву, вы просто require
form
с префиксом шляпы. Это позволяет сохранить ссылку в функции ссылок ваших директив:
module.directive('awesomeFormChild', [function () {
var formController;
return {
require: '^form',
link: function(scope, elm, attr, ctrl) {
formController = ctrl;
}
};
}])
Ответ 7
Ваш контроллер может находиться вне вашей формы, или вы пытаетесь получить форму до того, как форма будет заполнена в области.
Я создал PlunkR, и он хорошо работает.
Ответ 8
Что касается решения Sunil D. new для предоставления области формы родительским областям (см. fooobar.com/questions/329779/...), вы можете фактически получить область формы из объекта события, которая отправляется при вызове $emit.
Так как по крайней мере Angular 1.0.3, объект события имеет свойство targetScope, которое ссылается на область, в которой событие было испущено. (См. http://docs.angularjs.org/api/ng/type/ $rootScope.Scope # $для получения дополнительной информации о свойствах объекта события.)
Имея это в виду, вы можете упростить директивный код Сунил Д.:
module.directive('formLocator', function() {
return {
link: function(scope) {
scope.$emit('formLocator');
}
};
});
Шаблон не изменяется вообще:
<form name="myForm" novalidate="" form-locator>
И впоследствии вы измените код обработки событий:
$scope.$on('formLocator', function(event) {
$scope.myDeeplyNestedForm = event.targetScope.myForm;
});
Эта директива была бы релевантна в любом сценарии, где вы хотели бы предоставить область охвата одному из своих предков, а не только в случае ngForm. В моей кодовой базе я переименовал эту директиву в более общий "подарок", поскольку одним из способов думать о директивной цели является то, что она объявляет о наличии области.
Ответ 9
Я знаю, что это вызовет много ужасов.... но я был довольно ленив и использовал следующее (что я хотел бы верить, не создает больших накладных расходов из-за того, что их добавили в качестве часов и превзошли каждый дайджест)
<form name = "formName" nf-if="someCondition">
{{(controller.referenceToForm==undefined && (controller.referenceToForm=formName) != undefined)?'':''}}
</form>
Затем я просто использую controller.referenceToForm
внутри своего контроллера и т.д.
Ответ 10
Подобно решению Sunil D., я прошел через аналогичный, но неявно устанавливая переменную области видимости, formController, в которой использовался тег, поскольку я не хотел жестко кодировать имя формы дважды
renderFormModule.directive('formLocator', function() {
return {
link: function(scope, element) {
scope.formAssociated = scope[element[0].name];
}
}
});
И затем, вид что-то вроде:
<form name="testForm" ng-controller='formController as formCtrl' form-locator novalidate>