web-dev-qa-db-ja.com

親コントローラーのFormControllerまたはAngularJSのスコープにアクセスするにはどうすればよいですか?

複数のフォームがあるページがあり、一度に1つだけ表示したいと思います。このために、各フォームをセクションに分割し、Bootstrapのアコーディオンプラグインを使用して、一度に1つの開いているセクションのみを許可します。

私のマークアップは次のようになります。

_<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(){})で試しましたが、まだ定義されていません

  • フォームの名前を2番目のパラメーターとして_open_section_にopen_section('section1', section1Form)のように追加しようとしましたが、関数では2番目の引数はundefinedです。

_<form></form>_タグの間では、FormControllerにアクセスできますが、タグの外側ではアクセスできません。イベントは_<form>_(セクションの終了、開始)の外部から発生しているため、フォームの有効性を確認するためにFormControllerをコントローラーに渡すことができません。

これを回避する方法はありますか、それともページをリファクタリングする必要がありますか?

私はAngular 1.1.5ところで使用しています。

また、AngularJS Batarang Chromeプラグインを確認すると、フォームが子スコープとして現在のスコープに公開されていることがわかります。

[〜#〜] edit [〜#〜]:これはスコープ階層がこのアプリを探す方法です

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

これは、_ng-include_を使用しているためですか?それでは、コントローラーでこれらのフォームにアクセスする方法はありませんか?

16
adamors

動的フォーム、つまり関連する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;
});
16
Sunil D.

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>

「catcher。」に割り当てられているため、angularはスコープ階層を上に移動し、間にあるコントローラーの数に関係なく、mainControllerでそれを見つけます(コントローラーがない場合)もちろん、キャッチャーオブジェクト)

7
Abhinav Gujjar

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

ディレクティブ、コントローラーなどからフォームにアクセスするには、ng-initを使用できます。

例えば:

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

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

フォームデータにアクセスするか、これがディレクティブの場合はバインドされた変数で返すことができます。上記のテンプレートのコントローラーの例:

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

これは Sinil Dの答え すばらしい答えに似ています。つまり、フォームを親の$ scopeに保存しますが、イベントは使用しません。基本的に同じことをしますが、オーバーヘッドは少し少なくなります。

4
Eric G

角度のあるドキュメント で読むことができます:

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

フォームの名前。指定した場合、フォームコントローラーはこの名前で関連するスコープに公開されます。

ただし、 ngIf のように、新しいスコープを作成する特定のディレクティブがあります。

NgIfを使用して要素を削除すると、そのスコープが破棄され、要素が復元されたときに新しいスコープが作成されることに注意してください。

それはあなたの場合でしょうか?その場合は、フォーム名を「forms.section1Form」のように設定してから、スコープ内でそれに応じてアクセスしてみてください。

actualFormControllerが特定のディレクティブを担当するようにするには、単にrequireformに帽子のプレフィックスを付けます。これにより、ディレクティブのリンク関数に参照を保存できます。

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

    var formController;

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

}])
3
Philzen

フォームのスコープを親スコープに提供するためのSunilD。の新しいソリューション( https://stackoverflow.com/a/22487840/1518575 を参照)に関しては、実際にイベントからフォームのスコープを取得できます。 $ emit呼び出しで送信されるオブジェクト。

少なくともAngular 1.0.3であるため、イベントオブジェクトにはtargetScopeプロパティがあり、イベントが$ emitされたスコープを参照します( http:// docsイベントオブジェクトのプロパティの詳細については、.angularjs.org/api/ng/type / $ rootScope.Scope#$ onを参照してください。)

これを念頭に置いて、SunilD。のディレクティブコードを次のように簡略化できます。

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の場合だけでなく、その祖先の1つにスコープを提供する必要があるすべてのシナリオに関連します。私のコードベースでは、このディレクティブの名前をより一般的な「present」に変更しました。これは、ディレクティブの目的を考える1つの方法が、スコープの存在を通知することであるためです。

2
chrismendis

コントローラがフォームの外部にある可能性がありますORフォームがスコープに入力される前に、フォームを取得しようとしています。

PlunkR を作成しましたが、うまく機能しています。

2
L105

私はこれが多くの恐怖を引き起こすことを知っています....しかし私はかなり怠惰で、以下を使用しました(時計として追加され、すべてのダイジェストを実行するため、大きなオーバーヘッドが発生しないと信じたいです):

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

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

</form>

次に、コントローラーなどでcontroller.referenceToFormを使用します。

0
Menios

Sunil D.ソリューションと同様に、同様のソリューションに出くわしましたが、フォームの名前を2回ハードコーディングしたくなかったため、タグが使用された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>
0
lqbweb