スコープとテンプレートに対していくつかの操作を実行する必要があります。私は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
関数の意味は何ですか?
私のinitiallink
とcontroller
関数との闘争とそれらについてかなり読んだ後、私は今答えがあると思います。
最初にunderstandとします。
簡単に言えば、角度指示子はどのように機能しますか:
テンプレートから始めます(文字列として、または文字列にロードされます)
var templateString = '<div my-directive>{{5 + 10}}</div>';
さて、このtemplateString
はangle要素としてラップされています。
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
を呼び出します。
compilevslinkvscontrollerの比較:
すべての指令はコンパイル済みの1回のみで、link関数は再利用のために保持されます。したがって、ディレクティブのすべてのインスタンスに適用可能なものがある場合は、そのディレクティブのcompile
関数内で実行する必要があります。
これで、コンパイル後にtemplateをDOMにアタッチしながら実行される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/directive のmyTabs
の例のように)
(5)link
関数でもこれをすべて実行できたのは事実ですが、about懸念の分離です。
したがって、最後に、すべての部分に完全に適合する次のものがあります。
link
とcontroller
の違いは、DOMでディレクティブをネストし、親ディレクティブからネストされたディレクティブにAPI関数を公開する場合に役立ちます。
docs から:
ベストプラクティス:APIを他のディレクティブに公開する場合は、コントローラーを使用します。それ以外の場合はリンクを使用します。
my-form
とmy-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
関数を使用する必要はありません。さらに、link
とcontroller
の両方を定義する際に、2つの呼び出しの順序に注意する必要があります(controller
は前に実行されます)。
ただし、Angular wayに合わせて、ほとんどのDOM操作と$watchers
を使用した2方向バインディングは、通常、link
関数で行われます。子および$scope
操作用のAPIは、controller
で行われます。これは難しくて速い規則ではありませんが、そうすることでコードをよりモジュール化し、関心の分離に役立ちます(コントローラーはdirective
状態を維持し、link
関数はDOM
+外部バインディングを維持します)。
controller
関数/オブジェクトは抽象化モデル - ビュー - コントローラ(MVC)を表します。 MVCについて書くことに新しいことは何もありませんが、それは角度の最も重要な利点であり続けます:懸念をより小さな部分に分けます。それだけではありません。Model
から来るView
の変更に反応する必要がある場合は、Controller
がその作業を実行するための正しい person です。
link
関数についての話は異なります、それはMVCとは異なる観点から来ています。 controller/model/view
(template)の境界を越えたいのであれば、本当に重要です。
link
関数に渡されるパラメータから始めましょう:
function link(scope, element, 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);
});
...