javascript 如何访问父控制器中的 FormController 或 AngularJS 中的作用域

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19140386/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 14:32:13  来源:igfitidea点击:

How do I access FormController in parent controller or scope in AngularJS

javascriptangularjsformsangularjs-scope

提问by adamors

I have a page with multiple forms and I only want to show one at a time. For this I separated each form into a section and using Bootstrap's accordion plugin I only allow one open section at a time.

我有一个包含多个表单的页面,我只想一次显示一个。为此,我将每个表单分成一个部分,并使用 Bootstrap 的手风琴插件我一次只允许打开一个部分。

My markup looks something like this:

我的标记看起来像这样:

<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>

Everything work just fine, I can navigate between the forms etc.

一切正常,我可以在表单等之间导航。

Because I don't want the user opening a section if the one they are currently editing contains validation errors, I tried checking in the open_sectionfunction if the form associated with it is valid or not.

因为如果用户当前正在编辑的部分包含验证错误,我不希望用户打开该部分,所以我尝试检查open_section与其关联的表单是否有效。

I tried, but I could not. I could not access the FormController associated with the forms in the controller that is responsible for the page. For some reason, they are not getting published on the scope.

我试过了,但我做不到。我无法访问与负责页面的控制器中的表单关联的 FormController。出于某种原因,它们没有在范围内发布。

This is what I tried:

这是我尝试过的:

  • $scope.section1Formis undefined

  • tried with $scope.$watch('section1Form, function(){}), still undefined

  • tried adding the name of the form as a second parameter to open_sectionlike so: open_section('section1', section1Form)but in the function the second argument is undefined.

  • $scope.section1Formundefined

  • 尝试过$scope.$watch('section1Form, function(){}),仍然未定义

  • 尝试将表单的名称添加为第二个参数来open_section喜欢这样:open_section('section1', section1Form)但在函数中,第二个参数是undefined.

Between the <form></form>tags, I have access to the FormController, but outside them I don't. Since the event is coming from outside the <form>(the closing, opening of the sections) I can't pass the FormController to my controller to check the validity of my forms.

<form></form>标签之间,我可以访问 FormController,但在它们之外我不能。由于事件来自<form>(部分的关闭、打开)之外,我无法将 FormController 传递给我的控制器以检查表单的有效性。

Is there a way to get around this, or should I refactor my page?

有没有办法解决这个问题,还是应该重构我的页面?

I am using Angular 1.1.5 btw.

顺便说一句,我正在使用 Angular 1.1.5。

Also, checking with the AngularJS Batarang Chrome plugin, I can see that the forms get published as child scopes to the current scope.

此外,通过 AngularJS Batarang Chrome 插件检查,我可以看到表单作为子范围发布到当前范围。

EDIT: this is how the scope hierarchy looks for this app

编辑:这是范围层次结构查找此应用程序的方式

 - root
 |
 ---current controller\'s scope
 |
 ----scope that contains the forms

Is this because I'm using ng-include? Is there no way to access those forms in a controller then?

这是因为我正在使用ng-include吗?那么有没有办法在控制器中访问这些表单?

采纳答案by Sunil D.

To deal with dynamic forms, and thus the dynamic location of the associated FormController, I used a simple directive to help locate the scope that contains the form.

为了处理动态表单以及关联 FormController 的动态位置,我使用了一个简单的指令来帮助定位包含表单的范围。

Solution:

解决方案:

Create a directive that $emit's the scope associated w/the form:

创建一个指令, $emit 是与表单关联的范围:

  module.directive('formLocator', function() {
    return {
      link: function(scope) {
        scope.$emit('formLocator');
      }
    }

Use the directive in the markup:

在标记中使用指令:

<form name="myForm" novalidate form-locator>

Listen for the event broadcast by the directive in your controller:

监听控制器中指令广播的事件:

$scope.$on('formLocator', function(event) {
  $scope.myDeeplyNestedForm = event.targetScope.myForm;
});

回答by Abhinav Gujjar

There a much simpler way to communicate back up in the scope hierarchy by using angular process of looking for objects up in its scope hierarchy.

通过使用在其范围层次结构中向上查找对象的角度过程,有一种更简单的方法可以在范围层次结构中进行备份。

This allows us to attach the object from a lower scope into a higher scope by using the dot notation.

这允许我们使用点符号将对象从较低范围附加到较高范围。

In this case you need to create a "catcher" empty object on the top level controller. This catcher object can then be assigned the form objects from the lower scopes. Here is a plunk for demo.

在这种情况下,您需要在顶级控制器上创建一个“捕手”空对象。然后可以为该捕获器对象分配来自较低范围的表单对象。这是一个 plunk 演示。

http://plnkr.co/edit/xwsu48bjM3LofAoaRDsN?p=preview

http://plnkr.co/edit/xwsu48bjM3LofAoaARDsN?p=preview

It isn't perfectly elegant but if you think of this "catcher" object as an event listener, we're still following a standard pattern.

它并不完美,但如果您将这个“捕手”对象视为事件侦听器,我们仍然遵循标准模式。

create an empty catcher object in the controller where you'd like a reference to the nested form

在控制器中创建一个空的捕获器对象,您希望在其中引用嵌套表单

function mainController($scope){
  $scope.catcher = {

  };
 }

Then in the markup itself whenever the ng-form directive is declared, set catcher.formName = formName like so

然后在标记本身每当声明 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>

Because we're assigned to "catcher.", angular will traverse up the scope hierarchy and find thd it in the mainController regardless of any number of controllers in between (assuming they also don't have a catcher object, of course)

因为我们被分配给“catcher.”,angular 将遍历范围层次结构并在 mainController 中找到它,而不管它们之间有多少个控制器(当然,假设它们也没有 catcher 对象)

回答by adamors

Because I was using partial views with ng-viewthe forms were registered on a child scope of my controller. It seems that I cannot access the child scopes from a parent one, due to prototypical inheritance.

因为我使用的部分视图ng-view在我的控制器的子范围内注册了表单。由于原型继承,我似乎无法从父作用域访问子作用域。

That said, I did manage to get the form controller instances into my controller by passing them through the function that was responsible for opening/closing the accordion.

也就是说,我确实设法通过将表单控制器实例传递给负责打开/关闭手风琴的函数来将它们放入我的控制器中。

The solution is something like this:

解决方案是这样的:

<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>

回答by Eric G

To access the form from a directive, controller, etc... you can utilize ng-init:

要从指令、控制器等访问表单……您可以使用 ng-init:

For example:

例如:

  <form name="myForm">
     <div ng-init="myLocalScopeVar=form"></div

    <input name="myField" ....>
  </form>

You know can access the form data, or pass back with a bound variable if this is a directive. Example in the controller for the above template:

您知道可以访问表单数据,或者如果这是指令,则可以使用绑定变量传回。上述模板的控制器示例:

     if ($scope.myLocalScopeVar.myField.$valid ) ...

This is similar to Sinil D's answergreat answer, in that is saves the form onto the parent $scope, but it doesn't use events. It is essentially doing the same thing, but a bit less overhead.

这类似于Sinil D 的回答很好的答案,即将表单保存到父 $scope 上,但它不使用事件。它本质上是在做同样的事情,但开销要少一些。

回答by Filipe Miguel Fonseca

In the angular documentationone can read:

角度文档中,可以阅读:

<form
       [name="{string}"]>
</form>

Name of the form. If specified, the form controller will be published into related scope, under this name.

表格名称。如果指定,则表单控制器将在此名称下发布到相关范围。

However, there are certain directives, like ngIf, that create a new scope:

但是,有一些指令,比如ngIf,会创建一个新的作用域:

Note that when an element is removed using ngIf its scope is destroyed and a new scope is created when the element is restored.

请注意,当使用 ngIf 删除元素时,它的作用域被破坏,并在元素恢复时创建一个新的作用域。

Can that be your case? If so, you can try setting the form name to something like "forms.section1Form" and then access it accordingly in the scope.

你的情况可以这样吗?如果是这样,您可以尝试将表单名称设置为“forms.section1Form”之类的名称,然后在范围内相应地访问它。

回答by Philzen

To get the actualFormControllerresponsible for a certain directive, you simply requirethe formwith the hat prefix. This enables to store a reference in your directives' link function:

要获得实际FormController负责一定的指导,你只需requireform与帽子的前缀。这可以在指令的链接函数中存储引用:

module.directive('awesomeFormChild', [function () {

    var formController;

    return {
        require: '^form',
        link: function(scope, elm, attr, ctrl) {
            formController = ctrl;
        }
    };

}])

回答by L105

Your controller may be outside your form OR your are trying to get your form before the form is being populated in scope.

您的控制器可能在您的表单之外,或者您正在尝试在表单被填充到范围内之前获取您的表单。

I created a PlunkRand it working well.

我创建了一个PlunkR,它运行良好。

回答by chrismendis

Regarding Sunil D.'s novel solution to providing the form's scope to parent scopes (see https://stackoverflow.com/a/22487840/1518575), you can actually get the form's scope from the event object that is sent in an $emit call.

关于 Sunil D. 将表单的范围提供给父范围的新颖解决方案(请参阅https://stackoverflow.com/a/22487840/1518575),您实际上可以从以 $ 发送的事件对象中获取表单的范围发出呼叫。

Since at least Angular 1.0.3, the event object has a targetScope property, which references the scope on which the event was $emit-ed. (See http://docs.angularjs.org/api/ng/type/$rootScope.Scope#$on for more information about the properties of the event object.)

至少从 Angular 1.0.3 开始,事件对象有一个 targetScope 属性,它引用事件被 $emit-ed 的作用域。(有关事件对象的属性的更多信息,请参阅http://docs.angularjs.org/api/ng/type/$rootScope.Scope#$on。)

With this in mind, you can simplify Sunil D.'s directive code to be:

考虑到这一点,您可以将 Sunil D. 的指令代码简化为:

module.directive('formLocator', function() {
  return {
    link: function(scope) {
      scope.$emit('formLocator');
    }
  };
});

The template doesn't change at all:

模板根本没有改变:

<form name="myForm" novalidate="" form-locator>

And subsequently you would change the event handling code to be:

随后您将事件处理代码更改为:

$scope.$on('formLocator', function(event) {
  $scope.myDeeplyNestedForm = event.targetScope.myForm;
});

This directive would be relevant in any scenario where you would want to provide a scope to one of its ancestors, not just in the case of ngForm. In my codebase, I've renamed this directive to the more generic 'present', since one way to think of the directive's purpose is that it announces the presence of a scope.

该指令适用于您希望为其祖先之一提供范围的任何场景,而不仅仅是在 ngForm 的情况下。在我的代码库中,我已将此指令重命名为更通用的“present”,因为考虑该指令目的的一种方式是它宣布存在范围。

回答by Menios

I know this will cause a lot of horror.... but I was quite lazy and used the following (which I'd like to believe does not create massive overhead due to being added as a watch and excecute every digest):

我知道这会引起很多恐怖......但我很懒惰并使用了以下内容(我想相信由于被添加为手表并执行每个摘要而不会产生大量开销):

<form name = "formName" nf-if="someCondition">

{{(controller.referenceToForm==undefined && (controller.referenceToForm=formName) != undefined)?'':''}}

</form>

Then I just use controller.referenceToFormwithin my controller, etc.

然后我只是controller.referenceToForm在我的控制器中使用,等等。

回答by lqbweb

Similar to Sunil D. solution, I have come accross a similar one, but implicitly setting to the scope variable, the formController in which the tag was used on, as I did not want to hard code the name of the form twice:

与 Sunil D. 解决方案类似,我遇到了一个类似的解决方案,但隐式设置了范围变量,即使用标签的 formController,因为我不想对表单名称进行两次硬编码:

renderFormModule.directive('formLocator', function() {
    return {
        link: function(scope, element) {
            scope.formAssociated = scope[element[0].name];
        }
    }
});

And then, the view something like:

然后,视图类似于:

    <form name="testForm" ng-controller='formController as formCtrl' form-locator novalidate>