Angular JS:スコープを持つディレクティブのコントローラーがすでにある場合、ディレクティブのリンク関数の必要性は何ですか?


199

スコープとテンプレートに対していくつかの操作を実行する必要があります。私はそれをlink関数または関数のいずれかで行うことができるようですcontroller(両方がスコープにアクセスできるため)。

linkコントローラではなく関数を使用する必要があるのはいつですか?

angular.module('myApp').directive('abc', function($timeout) {
    return {
        restrict: 'EA',
        replace: true,
        transclude: true,
        scope: true,
        link: function(scope, elem, attr) { /* link function */ },
        controller: function($scope, $element) { /* controller function */ }
    };
}

また、それlinkは非角の世界であると理解しています。したがって、私は$watch$digestおよびを使用できます$apply

linkすでにコントローラーを持っている場合、機能の重要性は何ですか?


9
また、リンクは非角形の世界だと理解しています。だから$watch$digest$apply。を使用できます。」とはどういう意味ですか?
musically_ut

2
内部linkには角の魔法はありません。つまり、双方向のバインディングなどはありません。使用できるAngularのAPIがあるだけです。
Yugal Jindle 2013年

回答:


299

and 関数との最初の苦労とそれらについての多くを読んだ後、今、私は答えを持っていると思います。linkcontroller

最初に理解しましょ

角度指令はどのように機能するのですか?

  • テンプレートから始めます(文字列として、または文字列にロードされます)

    var templateString = '<div my-directive>{{5 + 10}}</div>';

  • これtemplateStringは、角度要素としてラップされています

    var el = angular.element(templateString);

  • ではelリンク関数$compileを取得するためにコンパイルします。

    var l = $compile(el)

    ここで何が起こるか、

    • $compile テンプレート全体を調べて、テンプレートが認識するすべてのディレクティブを収集します。
    • 検出されたすべてのディレクティブは再帰的にコンパイルされ、そのlink機能が収集されます。
    • 次に、すべてのlink関数が新しいlink関数にラップされ、として返されlます。
  • 最後に、scopeこのl(リンク)関数に関数を提供しますscope。これは、これとそれに対応する要素でラップされたリンク関数をさらに実行します。

    l(scope)

  • これは、追加templateの新しいノードとしてDOMおよび呼び出すcontrollerにその時計を追加しますスコープ DOM内のテンプレートと共有されています。

ここに画像の説明を入力してください

コンパイルリンクコントローラーの比較:

  • すべてのディレクティブは一度だけコンパイルされリンク関数は再利用のために保持されます。したがって、ディレクティブのすべてのインスタンスに適用できるものがある場合は、ディレクティブのcompile関数内で実行する必要があります。

  • これで、コンパイル後linkテンプレートDOMにアタッチしている間に実行される関数があります。したがって、ディレクティブのすべてのインスタンスに固有のすべてを実行します。たとえば、イベントのアタッチスコープ基づくテンプレートの変更など。

  • 最後に、コントローラーは、ディレクティブがDOM(接続された後)で機能している間、ライブおよびリアクティブで使用できるようになっています。したがって:

    (1)view [ V ](テンプレート)をリンクで設定した後。$scope私たちの[ M ]であり、MVCの$controller私たちの[ C ]

    (2)ウォッチを設定して、$ scopeとの双方向バインディングを利用します。

    (3)$scopeこれはランタイム中にテンプレートを監視しているものであるため、コントローラーに監視が追加されることが予想されます。

    (4)最後に、controller関連する指令間で通信できるようにするためにも使用されます。(https://docs.angularjs.org/guide/directiveのmyTabs例のように)

    (5)link関数内でもこれをすべて実行できたのは事実ですが、問題の分離についてです。

したがって、最後に、すべての部分に完全に適合する次のものが得られます。

ここに画像の説明を入力してください


5
この記事は、ここでの実行順序を理解するのにも役立ちます
。AngularJS

4
素晴らしい説明。コントローラはリンク関数の前に呼び出されることを述べておきたい。
jsbisht

38
コントローラはリンクの前に実行されます
Royi Namir

10
Stack Overflowは編集が少なくとも6文字であることを要求しているため、この回答のlet'sのスペルを修正することはできません。
user1886323

79

コントローラーが必要な理由

違いlinkとはcontroller、あなたのDOMに巣ディレクティブにしたいとネストされたものに親ディレクティブからAPI関数を公開したときに遊びに来ています。

ドキュメントから:

ベストプラクティス:APIを他のディレクティブに公開する場合は、コントローラーを使用します。それ以外の場合はリンクを使用します。

あなたは2つのディレクティブを持つようにしたいと言うmy-formmy-text-input、あなたがしたいmy-text-inputだけ内側に現れディレクティブmy-formとどこにも。

ディレクティブを定義しながら、その場合、あなたは言うだろうmy-text-input、それがあることが必要ですからコントローラparent:このような引数を、必要に使用してDOM要素をrequire: '^myForm'。これで、親要素のコントローラーは、に続く4番目の引数として関数にinjected入りlinkます$scope, element, attributes。そのコントローラーの関数を呼び出して、親ディレクティブと通信できます。

さらに、そのようなコントローラーが見つからない場合、エラーが発生します。

リンクを使用する理由

がで使用できるため、をlink定義しcontrollerている場合は、関数を使用する必要はありません。さらに、との両方を定義するとき、2つの呼び出しの順序(前に実行されます)に注意する必要があります。$scopecontrollerlinkcontrollercontroller

ただし、Angularの方法に合わせて、ほとんどのDOM操作と双方向のバインディングの使用$watchersは通常、link関数で行われますが、子と$scope操作のAPI はで行われますcontroller。これは難しい規則ではありませんが、そうすることでコードがよりモジュール化され、問題の分離に役立ちます(コントローラーはdirective状態を維持し、link関数はDOM+外部バインディングを維持します)。


それは素晴らしいことです。さて、質問の後半を手伝っていただけますか?
Yugal Jindle 2013年

つまり、他のディレクティブとの通信に使用できるコントローラが存在していたためです。それで、何が必要でしたlinkか?
Yugal Jindle 2013年

1
あなたの答えはどういうわけか実際の質問に答えません。
Yugal Jindle 2013年

1
を定義するときに発生する問題はありますcontrollerか?コントローラーの定義を避けるためだけに、まったく新しい関数を発明したいのはなぜですか?
Yugal Jindle 2013年

1
@scalaGirlのリンクが機能していないようです
港区

17

controller関数/オブジェクトは、抽象モデル・ビュー・コントローラ(MVC)を表します。MVCについて書くことは新しいことは何もありませんが、それでもAngularの最も重要な利点です。そして、それはあなたがに反応する必要があるそうならば、何よりも、それをだModelから、変更の権利である、そのジョブを実行します。ViewController

link機能についての話は異なります。MVCとは異なる視点から来ています。そしてcontroller/model/view (テンプレート)の境界を越えたいと思ったら、それは本当に重要です。

link関数に渡されるパラメーターから始めましょう。

function link(scope, element, attrs) {
  • scopeはAngularスコープオブジェクトです。
  • elementは、このディレクティブが一致するjqLit​​eでラップされた要素です。
  • attrsは、正規化された属性名とそれに対応する値を持つオブジェクトです。

linkコンテキストに入れるには、すべてのディレクティブがこの初期化プロセスのステップ(コンパイルリンク)を通過していることを言及する必要があります。Brad GreenとShyam Seshadriの本Angular JSからの抜粋:

コンパイルフェーズ(リンクの姉妹、明確に理解するためにここで言及しましょう):

このフェーズでは、AngularはDOMを調べて、テンプレートに登録されているすべてのディレクティブを識別します。次に、ディレクティブごとに、ディレクティブのルール(テンプレート、置換、トランスクルードなど)に基づいてDOMを変換し、コンパイル関数が存在する場合はそれを呼び出します。結果は、コンパイルされたテンプレート関数です。

リンクフェーズ

ビューを動的にするために、Angularは各ディレクティブに対してリンク関数を実行します。リンク関数は通常、DOMまたはモデルにリスナーを作成します。これらのリスナーは、ビューとモデルを常に同期させます。

の使用例としては、カスタムディレクティブの作成をlinkご覧ください。例を参照してください。「日時」をページに挿入するDOMを操作するディレクティブを作成し、毎秒更新します。

上記の豊富なソースからの非常に短いスニペットで、DOMによる実際の操作を示しています。$ timeoutサービスにフックされた関数があり、また、メモリリークを回避するためにデストラクタ呼び出しでクリアされます

.directive('myCurrentTime', function($timeout, dateFilter) {

 function link(scope, element, attrs) {

 ...

 // the not MVC job must be done
 function updateTime() {
   element.text(dateFilter(new Date(), format)); // here we are manipulating the DOM
 }

 function scheduleUpdate() {
   // save the timeoutId for canceling
   timeoutId = $timeout(function() {
     updateTime(); // update DOM
     scheduleUpdate(); // schedule the next update
   }, 1000);
 }

 element.on('$destroy', function() {
   $timeout.cancel(timeoutId);
 });

 ...

3
あなたは比較しているように見えるcompilerlink。彼らが質問したのは、なぜlink私たちがすでに持っていたのかを尋ねるcontroller
ユガルジンドル2013年

答えを拡張して、コントローラーについても詳しく説明しました。controllervs のコンセプトlinkがより明確になりました...
RadimKöhler、

1
私はその説明に落ち着くことを求めることができます。でも、ぼやけているようです。角度のあるチーム自体の誰かがそれについて話し、彼らがどこに行くのlinkか、またはどこに行くのかを予測できるといいですねcontroller
Yugal Jindle 2013年

1
それが私が理解したい唯一の部分です(いつそれは十分ではありませんか?)。プラス、私はの角度のすべての利点を取得controllerし、link比較的醜いです。したがって、角度のあるチームには、単なる選択肢ではなく、正当な理由があるはずです。
Yugal Jindle 2013年

1
質問:コントローラーが十分でない場合?回答: JQueryプラグインを使用したり、ドキュメント(docs.angularjs.org/api/ng/function/angular.element:)に記載されているJQlite機能を使用したりするなど、Angularの経験が必要な場合は、リンク
Hasteq 2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.