ディレクティブを定義するときの「コントローラー」、「リンク」、および「コンパイル」関数の違い


393

ディレクティブロジックにコントローラー関数を使用している場所と、リンクを使用している場所があります。アンギュラーホームページのタブの例では、1つのコントローラーを使用し、別のディレクティブのリンクを使用しています。2つの違いは何ですか?


回答:


635

私はあなたの質問を少し拡張し、コンパイル機能も含めます。

  • コンパイル関数 - テンプレート DOM操作(つまり、tElement =テンプレート要素の操作)に使用します。したがって、ディレクティブに関連付けられたテンプレートのすべてのDOMクローンに適用される操作です。(リンク関数(またはリンク前関数とリンク後関数)も必要で、コンパイル関数を定義した'link'場合、'compile'属性が定義されていると属性は無視されるため、コンパイル関数はリンク関数を返す必要があります。)

  • リンク関数 -通常、リスナーコールバック(つまり、$watchスコープの式)の登録とDOMの更新(つまり、iElementの操作=個々のインスタンス要素)に使用します。テンプレートが複製された後に実行されます。たとえば、内部で<li ng-repeat...>は、リンク関数は<li>、特定の<li>要素のテンプレート(tElement)が(iElementに)複製された後に実行されます。を$watch使用すると、ディレクティブにスコーププロパティの変更を通知できます(スコープは各インスタンスに関連付けられています)。これにより、ディレクティブは更新されたインスタンス値をDOMにレンダリングできます。

  • コントローラー関数 -別のディレクティブがこのディレクティブと対話する必要がある場合に使用する必要があります。たとえば、AngularJSのホームページでは、ペインディレクティブ自体をtabsディレクティブで管理されているスコープに追加する必要があるため、tabsディレクティブは、ペインディレクティブがアクセス/呼び出しできるコントローラーメソッド(APIを考える)を定義する必要があります。

    tabsとpaneディレクティブの詳細な説明、およびtabsディレクティブがthis(ではなく$scope)を使用してそのコントローラーに関数を作成する理由については、AngularJSコントローラーの「this」と$ scopeを参照してください。

一般に、メソッド$watchesなどをディレクティブのコントローラまたはリンク関数のいずれかに入れることができます。コントローラーが最初に実行されますが、これは重要な場合があります(ctrl関数とlink関数が2つのネストされたディレクティブで実行されたときにログを記録するこのフィドルを参照してください)。Joshがコメントで述べたように、フレームワークの他の部分との一貫性を保つために、スコープ操作関数をコントローラー内に配置することができます。


131
この説明は、それへの参照主AngularJSドキュメントまたは少なくともあるべきである
Dogoku

7
これは有益な答えですが、読みにくいと思います。句読点を増やし、文を短くすると役立つ場合があります。全体的に私は答えに感謝しています。
Marty Cortez

$ compilerは、 'compile'属性が存在する場合、 'link'属性を無視します。しかし、「コントローラー」属性がある場合はどうでしょうか。'controller'により、$ compilerは 'link'属性と 'compile'属性のいずれかまたは両方を無視しますか?「コントローラ」と一緒に「コンパイル」を使用することは可能ですか、または推奨されますか?
カールG

1
@CarlG、コントローラー属性の存在は、リンクとコンパイルに関して$ compilerに影響を与えません。コンパイルとコントローラーを使用できます。
Mark Rajcok 2014

1
「DOMリスナー」は「(つまり、スコープの$ watch式)」ではありません。1つはDOMなどのイベントをリッスンし、もう1つはmouseoverプロパティ変更のスコープをリッスンします。大きな違い。
ドミトリザイツェフ2015年

56

マークの答えを補足するものとして、コンパイル関数はスコープにアクセスできませんが、リンク関数はアクセスできます。

私はこのビデオを本当にお勧めします。Misko Hevery(AngularJSの父)によるディレクティブの作成。違いといくつかのテクニックについて説明しています。(ビデオの14:41マークでのコンパイル関数とリンク関数の違い)。


3
ビデオへのリンクの+1。それは非常に有益です。
Rob Kielty 2014


35
  1. コンパイル前にコードを実行:コントローラを使用
  2. コンパイル後にコードを実行:リンクを使用

角度規則:コントローラーにビジネスロジックを記述し、リンクにDOM操作を記述します。

これとは別に、別のディレクティブのリンク関数から1つのコントローラー関数を呼び出すことができます。たとえば、3つのカスタムディレクティブがあります。

<animal>
<panther>
<leopard></leopard>
</panther> 
</animal>

そして、「ヒョウ」指令の中から動物にアクセスしたいとします。

http://egghead.io/lessons/angularjs-directive-communicationは、ディレクティブ間の通信について知るのに役立ちます


18
「コンパイル前にコードを実行する:コントローラを使用する」。これは誤りです。compile常に に実行されcontrollerます。
Izhaki 14

(少なくとも簡単な方法では)ヒョウの指令から動物にアクセスすることはできません。子ディレクティブは親ディレクティブのコントローラーメソッドにアクセスできますが、兄弟ディレクティブ(上記の例のように)はお互いのコントローラーを呼び出すことができません。
ベンジャミンホワイト

2
ヒョウは本当に一種のパンサーですか?また、余談ですが、ディレクティブ内にリンクとコントローラがありますか?
Cody

1
はいヒョウ/ジャガーはヒョウです。はい、ディレクティブ内にリンクとコントローラーがあります。
Rahul、2014年

1
Angular開発者ガイド:「ベストプラクティス:APIを他のディレクティブに公開する場合はコントローラーを使用します。それ以外の場合はリンクを使用します。」
Martin van Driel、2015年

6

コンパイル機能 -

  1. コントローラとリンク関数の前に呼び出されます。
  2. コンパイル機能では、元のテンプレートDOMがあるので、AngularJSがインスタンスを作成する前、およびスコープが作成される前に、元のDOMに変更を加えることができます。
  3. ng-repeatは完璧な例です-元の構文はテンプレート要素であり、HTMLで繰り返される要素はインスタンスです
  4. 複数の要素インスタンスと1つのテンプレート要素のみが存在できます
  5. スコープはまだ利用できません
  6. コンパイル関数は関数とオブジェクトを返すことができます
  7. (リンク後)関数を返す-コンパイル関数が空の場合、configオブジェクトのlinkプロパティを介してリンク関数を登録するのと同じです。
  8. preおよびpostプロパティを介して登録された関数を含むオブジェクトを返す-リンク段階でリンク関数をいつ呼び出すかを制御できます。以下のリンク前およびリンク後の関数に関する情報を参照してください。

構文

function compile(tElement, tAttrs, transclude) { ... }

コントローラ

  1. コンパイル関数の後に呼び出されます
  2. スコープはここにあります
  3. 他のディレクティブからアクセスできます(require属性を参照)

事前リンク

  1. link関数は、DOMリスナーの登録とDOMの更新を担当します。テンプレートが複製された後に実行されます。これは、ほとんどのディレクティブロジックが配置される場所です。

  2. angular.elementを使用してコントローラーのdomを更新できますが、要素はリンク関数で提供されるため、これはお勧めできません

  3. 事前リンク関数は、angular jsが子要素をすでにコンパイルしたとき、ただし子要素のいずれかのポストリンクが呼び出される前に実行されるロジックを実装するために使用されます。

ポストリンク

  1. リンク関数のみを持つディレクティブ、angularは関数をポストリンクとして扱います

  2. postはコンパイル、コントローラー、プリリンク機能の後に実行されるので、これがディレクティブロジックを追加するための最も安全でデフォルトの場所であると考えられています

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.