One-way binding in AngularJS
AngularJS 1.5.x has been out for a few weeks now but, despite tracking the changelog, I missed a change that this version introduces: one-way binding in directives.
When you need to pass an argument to a directive, there are 3 ways of doing it:
-
using
@
, to pass a string value. You can pass a dynamic string by using mustaches:<my-directive name="{{ thePony.name }}"></my-directive>
-
using
=
, to pass an expression of any type:<my-directive pony="thePony"></my-directive>
-
using
&
, to pass some code that the directive is free to execute when it needs to:<my-directive on-selection="setSelectedPony(thePony)"></my-directive>`
The second way does more than that, though: it establishes a two-way binding between the directive scope’s pony
and the controller
scope’s thePony
:
- assigning a new value to
thePony
in the controller scope will assign a new value topony
in the directive scope; - assigning a new value to
pony
in the directive scope will assign a new value tothePony
in the controller scope; - changing an attribute (the color, for example) of
thePony
in the controller scope, will change the attribute inpony
, in the directive scope; - changing an attribute (the color, for example) of
pony
in the directive scope, will change the attribute inthePony
, in the controller scope.
Most of the time, the directive needs to get information from the controller, but doesn’t need to change that information. The second bullet point above is something we don’t really need. And this two-way binding has a certain cost.
Since AngularJS 1.5, it’s now possible to bind a value one-way, using <
:
- assigning a new value to
thePony
in the controller scope will assign a new value topony
in the directive scope; - assigning a new value to
pony
in the directive scope will not assign a new value tothePony
in the controller scope. Don’t do that, it’s nasty; - changing an attribute (the color, for example) of
thePony
in the controller scope, will change the attribute inpony
, in the directive scope: they both reference the same object; - changing an attribute (the color, for example) of
pony
in the directive scope, will change the attribute inthePony
, in the controller scope: they both reference the same object.
As far as I know, this has been done for several reasons:
- it aligns more closely with Angular2, where one-way binding is the norm;
- it allows to avoid making a copy of the object passed as argument to the directive;
- it allows creating a single watcher in the controller scope, that watches by identity instead of equality, making it faster.
More details are available in the documentation. You can also experiment with a little plunkr I wrote to show the difference of behavior between the two.
Enjoy!