AngularJS でディレクティブを記述する場合、新しいスコープが必要か、新しい子スコープが必要か、新しい分離スコープが必要かをどのように判断すればよいですか? 質問する

AngularJS でディレクティブを記述する場合、新しいスコープが必要か、新しい子スコープが必要か、新しい分離スコープが必要かをどのように判断すればよいですか? 質問する

新しいディレクティブを書くときにどのタイプのスコープを使用するかを判断するのに役立つガイドラインを探しています。理想的には、一連の質問に順に答えていくと正しい答え (新しいスコープなし、新しい子スコープなし、新しい分離スコープなし) が出てくるフローチャートのようなものが欲しいのですが、それはおそらく要求しすぎです。これが私の現在の貧弱なガイドラインです:

  • ディレクティブを使用する要素が ng-model を使用する場合は、分離スコープを使用しないでください。分離スコープで ng-model を使用できますか?および分離スコープでフォーマッタが機能しないのはなぜですか?
    を参照してください。
  • ディレクティブがスコープ/モデルプロパティを変更しない場合は、新しいスコープを作成しない
  • ディレクティブが DOM 要素のセットをカプセル化している場合 (ドキュメントでは「複雑な DOM 構造」と記載されています)、およびディレクティブが要素として使用される場合、または同じ要素に他のディレクティブがない場合、分離スコープは適切に機能するようです。

要素に分離スコープを持つディレクティブを使用すると、同じ要素の他のすべてのディレクティブが同じ (1 つの) 分離スコープを使用するように強制されることは承知していますが、分離スコープを使用できるタイミングが大幅に制限されるのではないでしょうか。

Angular-UI チーム (または多くのディレクティブを作成した他のメンバー) が経験を共有してくれることを期待しています。

「再利用可能なコンポーネントには分離されたスコープを使用する」というだけの回答は追加しないでください。

ベストアンサー1

素晴らしい質問ですね!他の人の意見も聞きたいですが、私が使っているガイドラインは次のとおりです。

高高度の前提: スコープは、親コントローラー、ディレクティブ、およびディレクティブ テンプレート間の通信に使用する「接着剤」として使用されます。

親スコープ: scope: false、新しいスコープはまったくありません

私はこれをあまり使用しませんが、@MarkRajcok が言ったように、ディレクティブがスコープ変数にアクセスしない場合 (そして明らかに何も設定しない場合)、私としてはこれで十分です。これは、親ディレクティブのコンテキストでのみ使用され (ただし、常に例外があります)、テンプレートを持たない子ディレクティブにも役立ちます。基本的に、テンプレートを持つものはスコープを共有するべきではありません。なぜなら、本質的にそのスコープをアクセスと操作のために公開しているからです (ただし、このルールには例外があると思います)。

一例として、私は最近、作成中の SVG ライブラリを使用して (静的な) ベクター グラフィックを描画するディレクティブを作成しました。このディレクティブには$observe2 つの属性 (widthheight) があり、計算にそれらを使用しますが、スコープ変数の設定や読み取りは行わず、テンプレートもありません。これは、別のスコープを作成しないのに適した使用例です。スコープは必要ないので、わざわざ作成する必要はありません。

But in another SVG directive, however, I required a set of data to use and additionally had to store a tiny bit of state. In this case, using the parent scope would be irresponsible (again, generally speaking). So instead...

Child Scope: scope: true

Directives with a child scope are context-aware and are intended to interact with the current scope.

Obviously, a key advantage of this over an isolate scope is that the user is free to use interpolation on any attributes they want; e.g. using class="item-type-{{item.type}}" on a directive with an isolate scope will not work by default, but works fine on one with a child scope because whatever is interpolated can still by default be found in the parent scope. Also, the directive itself can safely evaluate attributes and expressions in the context of its own scope without worrying about pollution in or damage to the parent.

For example, a tooltip is something that just gets added; an isolate scope wouldn't work (by default, see below) because it is expected that we will use other directives or interpolated attributes here. The tooltip is just an enhancement. But the tooltip also needs to set some things on the scope to use with a sub-directive and/or template and obviously to manage its own state, so it would be quite bad indeed to use the parent scope. We are either polluting it or damaging it, and neither is bueno.

I find myself using child scopes more often than isolate or parent scopes.

Isolate scope: scope: {}

This is for reusable components. :-)

But seriously, I think of "reusable components" as "self-contained components". The intent is that they are to be used for a specific purpose, so combining them with other directives or adding other interpolated attributes to the DOM node inherently doesn't make sense.

To be more specific, anything needed for this standalone functionality is provided through specified attributes evaluated in the context of the parent scope; they are either one-way strings ('@'), one-way expressions ('&'), or two-way variable bindings ('=').

On self-contained components, it doesn't make sense to need to apply other directives or attributes on it because it exists by itself. Its style is governed by its own template (if necessary) and can have the appropriate content transcluded (if necessary). It's standalone, so we put it in an isolate scope also to say: "Don't mess with this. I'm giving you a defined API through these few attributes."

A good best practice is to exclude as much template-based stuff from the directive link and controller functions as possible. This provides another "API-like" configuration point: the user of the directive can simply replace the template! The functionality all stayed the same, and its internal API was never touched, but we can mess with styling and DOM implementation as much as we need to. ui/bootstrap is a great example of how to do this well because Peter & Pawel are awesome.

Isolate scopes are also great for use with transclusion. Take tabs; they are not only the whole functionality, but whatever is inside of it can be evaluated freely from within the parent scope while leaving the tabs (and panes) to do whatever they want. The tabs clearly have their own state, which belongs on the scope (to interact with the template), but that state has nothing to do with the context in which it was used - it's entirely internal to what makes a tab directive a tab directive. Further, it doesn't make much sense to use any other directives with the tabs. They're tabs - and we already got that functionality!

Surround it with more functionality or transclude more functionality, but the directive is what it is already.

All that said, I should note that there are ways around some of the limitations (i.e. features) of an isolate scope, as @ProLoser hinted at in his answer. For example, in the child scope section, I mentioned interpolation on non-directive attributes breaking when using an isolate scope (by default). But the user could, for example, simply use class="item-type-{{$parent.item.type}}" and it would once again work. So if there is a compelling reason to use an isolate scope over a child scope but you're worried about some of these limitations, know that you can work around virtually all of them if you need to.

Summary

Directives with no new scope are read-only; they're completely trusted (i.e. internal to the app) and they don't touch jack. Directives with a child scope add functionality, but they are not the only functionality. Lastly, isolate scopes are for directives that are the entire goal; they are standalone, so it's okay (and most "correct") to let them go rogue.

I wanted to get my initial thoughts out, but as I think of more things, I'll update this. But holy crap - this is long for an SO answer...


PS: Totally tangential, but since we're talking about scopes, I prefer to say "prototypical" whereas others prefer "prototypal", which seems to be more accurate but just rolls off the tongue not at all well. :-)

おすすめ記事