[解決済み】AngularJSでディレクティブを書くとき、新しいスコープ、新しい子スコープ、または新しい分離されたスコープが必要であるかどうかは、どのように決定するのですか?
質問
新しいディレクティブを書くときに、どのタイプのスコープを使うべきかを判断するのに役立つガイドラインを探しています。理想を言えば、フローチャートのようなもので、いくつかの質問に答えていくと、正しい答え(新しい新しいスコープ、新しい子スコープ、新しいアイソレートスコープ)が出てくるようなものがいいのですが、それはあまりに無理な注文でしょう。以下は、私の現在のわずかなガイドラインです。
-
ディレクティブを使用する要素が ng-model を使用している場合、分離されたスコープを使用しないでください。
参照 孤立したスコープで ng-model を使用できますか? と
分離されたスコープでフォーマッタが機能しないのはなぜですか? - ディレクティブがスコープやモデルのプロパティを変更しないのであれば、 新しいスコープを作らないでください。
- ディレクティブが一連の DOM 要素をカプセル化している場合、スコープの分離はうまくいくようです ( ドキュメント には "a complex DOM structure" と書かれています) そして、ディレクティブは一つの要素として、あるいは、同じ要素に他のディレクティブがない状態で使用されるでしょう。
ある要素で孤立したスコープを持つディレクティブを使用すると、その同じ要素上の他のすべてのディレクティブが同じ(1つの)孤立したスコープを使用することを強制されることは承知していますが、これは孤立したスコープが使用できる場合を著しく制限しませんか。
Angular-UIチーム(または多くのディレクティブを書いたことのある他の人)が、その経験を共有してくれることを期待しています。
単に "再利用可能なコンポーネントのために分離されたスコープを使用する" と言う答えを追加しないでください。
どのように解決するのですか?
なんという素晴らしい質問でしょう。私は 愛 他の人の意見も聞いてみたいですが、私が使っているガイドラインは以下の通りです。
高所作業前提:スコープは、親コントローラ、ディレクティブ、ディレクティブテンプレートの間の通信に使う "glue" として使用されます。
親スコープのこと。
scope: false
ということで、新しいスコープは全くありません。
私はこの方法をあまり使いませんが、@MarkRajcok が言ったように、ディレクティブがスコープ変数にアクセスしない(そして明らかに何も設定しない!)なら、私に関する限り、これはちょうどいいのです。これはまた、子ディレクティブが のみ 親ディレクティブのコンテキストで使用され (ただし、これには常に例外があります)、テンプレートがないもの。基本的に、テンプレートを持つものはスコープを共有することには適しません。なぜなら、アクセスや操作のためにスコープを公開することになるからです(ただし、このルールには例外があると思います)。
例として、私は最近、私が書きかけのSVGライブラリを使って(静的な)ベクターグラフィックを描くディレクティブを作成しました。それは
$observe
の2つの属性(
width
と
height
を使用しますが、スコープ変数の設定も読み込みもせず、テンプレートも持ちません。これは、もうひとつのスコープを作らないという意味では、良い使用例です。
しかし、別のSVGディレクティブでは、使用するデータセットが必要で、さらに、ほんの少しの状態を保存する必要がありました。この場合、親スコープを使うのは無責任です(これも一般論ですが)。そこで、代わりに...
子スコープです。
scope: true
子スコープを持つディレクティブはコンテキストを認識し、現在のスコープと対話することを意図しています。
明らかに、分離型スコープと比較した場合の主な利点は、ユーザーが望む属性に自由に補間を使用できることです。
class="item-type-{{item.type}}"
はデフォルトでは動作しませんが、子スコープを持つディレクティブでは問題なく動作します。なぜなら、補間されるものはデフォルトで親スコープに存在するからです。また、ディレクティブ自身は、親の汚染を心配することなく、自分のスコープのコンテキストで安全に属性や式を評価することができます。
例えば、ツールチップはただ追加されるものです。他のディレクティブや補間された属性をここで使用することが予想されるため、分離スコープは機能しません(デフォルトで、以下を参照ください)。ツールチップは単なる機能拡張です。しかし、tooltip はサブディレクティブやテンプレートで使用するためにスコープにいくつかのものを設定する必要があり、明らかにそれ自身の状態を管理するため、親スコープを使用することは非常に悪いことです。そのため、親スコープを使用することは非常に悪いことです。
私は、孤立スコープや親スコープよりも、子スコープを使うことが多いと感じています。
アイソレートスコープ。
scope: {}
これは再利用可能なコンポーネントのためのものです :-)
でも、真面目な話、quot;再利用可能なコンポーネントとは、quot;自己完結型のコンポーネントだと考えています。その意図は、特定の目的のために使用されることであり、他のディレクティブと組み合わせたり、DOMノードに他の補間属性を追加することは、本来は意味を持ちません。
具体的には、このスタンドアロン機能に必要なものは、親スコープのコンテキストで評価される指定された属性を通じて提供されます。これらは、一方向の文字列('@')、一方向の式('&')、または双方向の変数結合('=')となります。
自己完結型のコンポーネントでは、それ自体が存在するため、他のディレクティブや属性を適用する必要がないのが特徴です。そのスタイルは、(必要であれば)それ自身のテンプレートによって管理され、(必要であれば)適切なコンテンツをトランスクルードさせることができます。これはスタンドアロンなので、私たちはこれを孤立したスコープに置いて、次のように言っています: "これをいじってはいけません。私は、これらのいくつかの属性を通じて、定義されたAPIを提供します。
良いベストプラクティスは、ディレクティブリンクとコントローラ関数から、テンプレートベースのものをできるだけ除外することです。これは、もうひとつの API ライクな設定ポイントを提供します。機能はすべて同じままで、その内部APIは決して触られていませんが、必要なだけスタイルとDOMの実装をいじることができます。ui/bootstrapは 大 Peter & Pawelは素晴らしいので、これをうまくやる方法の例です。
アイソレート・スコープもトランスクルージョンと一緒に使うのに最適です。タブを例にとると、機能全体だけでなく、何であれ 内部 タブ(とペイン)に好きなことをさせながら、その親スコープから自由に評価することができるのです。タブは明らかに自分の 状態 しかし、その状態は、それが使われたコンテキストとは関係なく、タブディレクティブをタブディレクティブたらしめているのは、完全に内部的なものなのです。さらに、他のディレクティブをタブに使用することはあまり意味がありません。タブはタブであり、その機能はすでに持っているのですから。
より多くの機能で囲むか、より多くの機能を転記するか、しかしディレクティブはすでにあるものなのです。
とはいえ、@ProLoser氏の回答で示唆されているように、アイソレートスコープの制限(=特徴)のいくつかを回避する方法があることに留意しておく必要があります。例えば、子スコープセクションで、(デフォルトで)アイソレートスコープを使用すると、非ディレクティブ属性の補間が壊れると書きました。しかし、ユーザーは、例えば、単純に
class="item-type-{{$parent.item.type}}"
で、再び動作するようになります。ですから、もし子スコープよりも分離スコープを使うべきやむを得ない理由があるけれども、これらの制限のいくつかを心配しているのなら、必要なら事実上すべての制限を回避することができることを知っておいてください。
概要
新しいスコープを持たないディレクティブは読み取り専用で、完全に信頼され(つまりアプリの内部で)、ジャックに触れることはありません。子スコープを持つディレクティブ 追加 の機能を持ちますが、それらは 唯一の 機能です。最後に、分離スコープは、ゴール全体であるディレクティブのためのものです。それらはスタンドアロンなので、それらを不正に動作させても問題ありません(そして最も"正しい")。
最初に考えたことを吐き出したかったのですが、またいろいろ思いついたら、更新します。しかし、なんてこった......SOの回答にしては長いな......。
PS: 全く余談ですが、スコープについて話しているので、私は"prototypical"と言うのが好きなのですが、他の人は"prototypal"を好み、より正確に見えるけど舌触りは全く良くないですね :-)。
関連
-
[解決済み】angularのonLoadとng-initの違いについて
-
[解決済み] Angular ng-repeatの条件付きラップアイテム(ng-repeatのグループアイテム)。
-
[解決済み] Apigee API へのリクエストで 401 レスポンスエラーが発生する
-
[解決済み] AngularJS 。scope.apply()呼び出し時の$digest already in progressエラーを防ぐ。
-
[解決済み] AngularJSを使用して、ブラウザのコンソールで$scope変数にアクセスするにはどうすればよいですか?
-
[解決済み] AngularJSで$scope.$watchと$scope.$applyを使用するにはどうすればよいですか?
-
[解決済み] 入力フィールドにフォーカスを当てるには?
-
[解決済み] 子コントローラから親スコープにアクセスするAngularJS
-
[解決済み】AngularJSのディレクティブスコープにおける「@」と「=」の違いは何ですか?
-
[解決済み】ディレクティブ定義のtranscludeオプションの理解?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] AngularJSで$httpリクエスト中にスピナーGIFを表示する?
-
[解決済み】Angular ui-routerで$stateメソッドを$stateChangeStart toStateとfromStateで使用する。
-
[解決済み] 適用がすでに進行中のエラー
-
[解決済み] AngularJSのディープリンクとは何ですか?
-
[解決済み] AngularJSのシンプルな "Hello, world "が動作しない。
-
[解決済み] エラーです。[$injector:unpr] 不明なプロバイダです。ルートプロバイダ
-
[解決済み] 新しい/分離されたスコープを求める複数のディレクティブ [ngController, ...] がある。
-
[解決済み] ng-pattern` - 数字だけをチェックする方法は?
-
[解決済み] Angularjsを使用してローカルストレージにデータを保存するにはどうすればよいですか?
-
[解決済み] AngularJS: ngRouteが動作しない。