簡體   English   中英

如何在AngularJS中的父控制器或作用域中訪問FormController

[英]How do I access FormController in parent controller or scope in 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(){}) ,仍未定義

  • 嘗試將表單的名稱添加為open_section的第二個參數, open_section所示: open_section('section1', section1Form)但在函數中第二個參數undefined

<form></form>標簽之間,我可以訪問FormController,但在我們之外我沒有。 由於事件來自<form> (關閉,打開部分),我無法將FormController傳遞給我的控制器來檢查我的表單的有效性。

有沒有辦法解決這個問題,還是應該重構我的頁面?

我正在使用Angular 1.1.5順便說一句。

另外,使用AngularJS Batarang Chrome插件進行檢查,我可以看到表單作為子范圍發布到當前范圍。

編輯 :這是范圍層次結構查找此應用程序的方式

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

這是因為我使用的是ng-include嗎? 那么在控制器中無法訪問這些表單嗎?

為了處理動態表單,以及相關FormController的動態位置,我使用了一個簡單的指令來幫助定位包含表單的范圍。

解:

創建一個指令$ emit發出與表單關聯的范圍:

  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;
});

通過使用在其范圍層次結構中查找對象的角度過程,可以更簡單地在范圍層次結構中進行備份通信。

這允許我們使用點表示法將對象從較低的范圍附加到較高的范圍。

在這種情況下,您需要在頂級控制器上創建一個“捕手”空對象。 然后可以為較低范圍分配此捕獲器對象的表單對象。 這是一個演示的插件。

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>

因為我們被分配到“catcher。”,angular將遍歷范圍層次結構並在mainController中找到它,而不管它們之間是否有任何數量的控制器(當然,假設它們也沒有捕獲器對象)

因為我使用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>

角度文檔中,可以閱讀:

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

表格的名稱。 如果指定,表單控制器將以此名稱發布到相關范圍。

但是,有一些指令,如ngIf ,可以創建一個新范圍:

請注意,使用ngIf刪除元素時,其范圍將被銷毀,並且在還原元素時會創建新范圍。

這可能是你的情況嗎? 如果是這樣,您可以嘗試將表單名稱設置為“forms.section1Form”之類的內容,然后在范圍內相應地訪問它。

要從指令,控制器等訪問表單,您可以使用ng-init:

例如:

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

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

您知道可以訪問表單數據,或者如果這是指令,則使用綁定變量傳回。 上述模板的控制器示例:

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

這類似於Sinil D的回答很好的答案,即將表單保存到父$ scope,但它不使用事件。 它本質上是在做同樣的事情,但開銷要少一些。

要使實際的 FormController負責某個指令,您只require帶有hat前綴的form 這樣可以在指令的link函數中存儲引用:

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

    var formController;

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

}])

您的控制器可能在您的表單之外,或者您正在嘗試在表單填充范圍之前獲取表單。

我創建了一個PlunkR ,它運行良好。

關於Sunil D.為父范圍提供表單范圍的新穎解決方案(請參閱https://stackoverflow.com/a/22487840/1518575 ),您實際上可以從$中發送的事件對象中獲取表單的范圍。發出電話。

至少從Angular 1.0.3開始,事件對象具有targetScope屬性,該屬性引用事件為$ emit-ed的范圍。 (有關事件對象屬性的更多信息,請參閱http://docs.angularjs.org/api/ng/type/ $ rootScope.Scope#$ on。)

考慮到這一點,您可以將Sunil D.的指令代碼簡化為:

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的情況下。 在我的代碼庫中,我已將此指令重命名為更通用的'present',因為考慮該指令的目的的一種方法是它宣布存在范圍。

我知道這會引起很多恐怖....但我很懶惰並且使用了以下內容(我希望相信它不會因為被添加為手表並且超出每個摘要而產生巨大的開銷):

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

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

</form>

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

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM