web-dev-qa-db-ja.com

Angular JS:既にディレクティブのスコープ付きコントロールがある場合、ディレクティブのリンク機能は何かが必要ですか?

スコープとテンプレートに対していくつかの操作を実行する必要があります。私は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関数の意味は何ですか?

191
Yugal Jindle

私のinitiallinkcontroller関数との闘争とそれらについてかなり読んだ後、私は今答えがあると思います。

最初にunderstandとします。

簡単に言えば、角度指示子はどのように機能しますか:

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

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

  • さて、このtemplateStringangle要素としてラップされています。

    var el = angular.element(templateString);

  • elでは、link関数に戻るために$compileでコンパイルします。

    var l = $compile(el)

    これが起こるのです、

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

    l(scope)

  • これはtemplateを新しいノードとしてDOMに追加し、そのウォッチをDOMのテンプレートと共有されるscopeに追加するcontrollerを呼び出します。

enter image description here

compilevslinkvscontrollerの比較:

  • すべての指令はコンパイル済みの1回のみで、link関数は再利用のために保持されます。したがって、ディレクティブのすべてのインスタンスに適用可能なものがある場合は、そのディレクティブのcompile関数内で実行する必要があります。

  • これで、コンパイル後にtemplateDOMにアタッチしながら実行されるlink関数ができました。そのため、ディレクティブのすべてのインスタンスに固有のものすべてを実行します。例えば:attach eventsスコープに基づいてテンプレートを変更するなど。

  • 最後に、controllerは、ディレクティブがDOMに対して動作している間(接続された後)、有効で反応的になるように使用できるようになっています。したがって:

    (1)リンク付きビュー[V](すなわちテンプレート)を設定した後。 $scopeは私たちの[M]、$controllerは私たちの[C]MVC

    (2)2-way$ scopeとバインドしてウォッチを設定します。

    (3)$scopeウォッチは実行時にテンプレートを監視しているものであるため、コントローラに追加されることが期待されています。

    (4)最後に、controllerは関連するディレクティブ間で通信できるようにするためにも使用されます。 ( https://docs.angularjs.org/guide/directivemyTabsの例のように)

    (5)link関数でもこれをすべて実行できたのは事実ですが、about懸念の分離です。

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

enter image description here

291
Yugal Jindle

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

linkcontrollerの違いは、DOMでディレクティブをネストし、親ディレクティブからネストされたディレクティブにAPI関数を公開する場合に役立ちます。

docs から:

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

my-formmy-text-inputの2つのディレクティブを使用し、my-text-inputディレクティブをmy-formの内部にのみ表示し、それ以外の場所には表示しないとします。

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

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

リンクを使用する理由

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

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

72
musically_ut

controller関数/オブジェクトは抽象化モデル - ビュー - コントローラ(MVC)を表します。 MVCについて書くことに新しいことは何もありませんが、それは角度の最も重要な利点であり続けます:懸念をより小さな部分に分けます。それだけではありません。Modelから来るViewの変更に反応する必要がある場合は、Controllerがその作業を実行するための正しい person です。

link関数についての話は異なります、それはMVCとは異なる観点から来ています。 controller/model/view(template)の境界を越えたいのであれば、本当に重要です。

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

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

linkをコンテキストに入れるには、すべてのディレクティブがこの初期化プロセスのステップを踏んでいることに注意してください。 Compile Link Brad GreenとShyam Seshadriの本Angular JS からの抜粋:

コンパイルフェーズ(リンクの姉妹、わかりやすい画像を得るためにここで言及しましょう):

このフェーズでは、AngularがDOMを調べて、テンプレートに登録されているすべてのディレクティブを識別します。ディレクティブごとに、ディレクティブの規則(template、replace、transcludeなど)に基づいて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);
 });

 ...
15
Radim Köhler