AngularJS: overview of directive scopes
¶ by Rob FrieselI gave a talk on AngularJS directives recently and a good portion of that talk focused on defining the types of scopes that those directives can have. As something that the talk’s attendees could refer back to, I decided to put together this short blog post. It captures the spirit (if not the exact words) of what I presented that day. So without further ado…
scopes: an overview
One way to think about scope
objects on an AngularJS directive is to think of it as a little sandbox for the directive’s model data. The directive is able to participate in the application’s $digest
cycle, but we’re also able to carve off pieces that we can safely modify without “polluting” or “damaging” the parent scope. (Except when we want to.) This safety is the main reason that I’ve advocated so strongly for the liberal use of directives in AngularJS application design. When defining a directive, the value (or lack thereof) assigned to the scope
property of the directive definition object will determine what type of scope is created. At a high level, these scopes include: parent, new, and isolate.
parent scope
This one’s easy. If we leave off the scope
property from the directive definition object, then it (the directive) does not create a new scope, and instead inherits one from its parent (e.g., the controller). This implicitly creates a two-way binding for all properties on the parent scope; there is no inheritance, we’re simply dealing directly with the same scope as our parent.
new scope
This one’s only slightly trickier. If we set scope:true
on the directive definition object, then AngularJS kicks in the prototypal inheritance and creates a new version of the parent scope for the directive. I’d say that this is a quick way to create a directive with one-way bindings for all the properties on the parent scope but… When we stop and consider how JavaScript’s prototypal inheritance works with reference types, it’s easy to see where we would (potentially) inadvertantly start screwing up data on our parent scope. Observe the difference between how the scope bindings work for the ddc-presenter
and ddc-foo
directives in this fiddle:
isolate scopes
Where the AngularJS scope directives really shine is in the isolate scopes. These are those safe little sandboxes I alluded to earlier. By declaring the scope
property on the directive definition object with an object, we are creating an entirely new scope that is isolated from the parent with no inheritance from it. While this doesn’t necessarily mean that we can manipulate data with impunity, it does offer us some protection against accidentally mangling data from our parent scopes. We still have access to our parent scope (through the $parent
property) if we really need it, but we’re no longer working with it incidentally.
The other important thing to know about isolate scopes is that properties are declared with one of three special symbols to indicate the type of binding. Those symbols are:
@
for one-way bindings=
for two-bindings&
for expression bindings
@
The @
(one-way) binding uses interpolated literals to initialize a value on the directive’s isolate scope that is a copy of that value from the parent scope. The “copying” takes place during the directive’s linking phase and once complete, we can update that value indefinitely without overwriting the value on the parent scope. Observe:
=
The =
(two-way) binding allows us to keep values synchronized between the directive’s isolate scope and the parent scope. During the linking phase, a reference is created between the two scopes such that updates to one will reflect in the other (and vice versa). In some ways, this is what we get with the parent scope option (above) except that we are making explicit bindings to a specific subset of the properties on the parent scope. Observe:
&
The &
(expression) binding allows us to call functions from the parent scope within the context of the isolate scope. This allows us to create generic directives effectively have an interface that needs to be implemented with methods from that parent scope. Observe:
To sum up
AngularJS directives provide three different scopes to use for interacting with the data from parents scopes. We can omit the scope
property when defining our directive and simply use the parent scope. We can set scope:true
to create a new scope that prototypically inherits from the parent. And lastly, we can create an isolate scope to create a “sandboxed” context for the directive’s data. While all three have their uses, we should prefer the isolate scope for the flexibility and safety that it gives us.
About Rob Friesel
Software engineer by day. Science fiction writer by night. Weekend homebrewer, beer educator at Black Flannel, and Certified Cicerone. Author of The PhantomJS Cookbook and a short story in Please Do Not Remove. View all posts by Rob Friesel →One Response to AngularJS: overview of directive scopes
Pingback: SCOPE TRONG ANGULAR JS - AI Design - Thiết kế web theo yêu cầu tại Hồ Chà Minh
Leave a Reply