When writing a directive in AngularJS, how do I decide if I need no new scope, a new child scope, or a new isolated scope?


Answers

My personal policy and experience:

Isolated: a private sandbox

I want to create a lot of scope methods and variables that are ONLY used by my directive and are never seen or directly accessed by the user. I want to whitelist what scope data is available to me. I can use transclusion to allow the user to jump back in at the parent scope (unaffected). I do NOT want my variables and methods accessible in transcluded children.

Child: a subsection of content

I want to create scope methods and variables that CAN be accessed by the user, but are not relevant to surrounding scopes (siblings and parents) outside the context of my directive. I also would like to let ALL parent scope data to trickle down transparently.

None: simple, read-only directives

I don't really need to mess with scope methods or variables. I'm probably doing something that doesn't have to do with scopes (such as displaying simple jQuery plugins, validation, etc).

Notes

  • You should not let ngModel or other things directly impact your decision. You can circumvent odd behavior by doing things like ng-model=$parent.myVal (child) or ngModel: '=' (isolate).
  • Isolate + transclude will restore all normal behavior to sibling directives and returns to the parent scope, so don't let that affect your judgement either.
  • Don't mess with the scope on none because it's like putting data on scope for the bottom half of the DOM but not the top half which makes 0 sense.
  • Pay attention to directive priorities (don't have concrete examples of how this can affect things)
  • Inject services or use controllers to communicate across directives with any scope type. You can also do require: '^ngModel' to look in parent elements.
Question

I'm looking for some guidelines that one can use to help determine which type of scope to use when writing a new directive. Ideally, I'd like something similar to a flowchart that walks me through a bunch of questions and out pops the correct answer – no new new scope, new child scope, or new isolate scope – but that is likely asking for too much. Here's my current paltry set of guidelines:

I'm aware that using a directive with an isolated scope on an element forces all other directives on that same element to use the same (one) isolate scope, so doesn't this severely limit when an isolate scope can be used?

I am hoping that some from the Angular-UI team (or others that have written many directives) can share their experiences.

Please don't add an answer that simply says "use an isolated scope for reusable components".




Just thought I'd add my current understanding and how it relates to other JS concepts.

Default (e.g. not declared or scope: false)

This is philosophically equivalent to using global variables. Your directive can access everything in the parent controller but it is also affecting them and being affected at the same time.

scope:{}

This is like a module, anything it wants to use needs to be passed in explicitly. If EVERY directive you use is an isolate scope it can be the equivalent of making EVERY JS file you write its own module with a lot of overhead in injecting all the dependencies.

scope: child

This is the middle ground between global variables and explicit passthrough. It's similar to javascript's prototype chain and just extends you a copy of the parent scope. If you create an isolate scope and pass in every attribute and function of the parent scope it is functionally equivalent to this.


The key is that ANY directive can be written ANY way. The different scope declarations are just there to help you organize. You can make everything a module, or you can just use all global variables and be very careful. For ease of maintenance though it's preferable to modularalize your logic into logically coherent parts.There is a balance between an open meadow and a closed jail-house. The reason this is tricky I believe is that when people learn about this they think they are learning about how directives work but actually they are learning about code/logic organization.

Another thing that helped me figure out how directives work is learning about ngInclude. ngInclude helps you include html partials. When I first started using directives I found that you could use it's template option to reduce your code but I wasn't really attaching any logic.

Of course between angular's directives and the work of the angular-ui team I haven't yet had to create my own directive that does anything substantial so my view on this may be completely wrong.






Links