1106

I've read the AngularJS documentation on the topic carefully, and then fiddled around with a directive. Here's the fiddle.

And here are some relevant snippets:

  • From the HTML:

    <pane bi-title="title" title="{{title}}">{{text}}</pane>
    
  • From the pane directive:

    scope: { biTitle: '=', title: '@', bar: '=' },
    

There are several things I don't get:

  • Why do I have to use "{{title}}" with '@' and "title" with '='?
  • Can I also access the parent scope directly, without decorating my element with an attribute?
  • The documentation says "Often it's desirable to pass data from the isolated scope via expression and to the parent scope", but that seems to work fine with bidirectional binding too. Why would the expression route be better?

I found another fiddle that shows the expression solution too: http://jsfiddle.net/maxisam/QrCXh/

Arsen Khachaturyan
  • 7,904
  • 4
  • 42
  • 42
iwein
  • 25,788
  • 10
  • 70
  • 111
  • 18
    Fair point. Ability to research and find answers is important. – Jonathan May 07 '15 at 13:43
  • 1
    http://stackoverflow.com/questions/14908133/what-is-the-difference-between-vs-and-in-angularjs – zloctb Aug 29 '15 at 11:18
  • 1
    In simple words `=` is used in directive isolate scope to enable two way binding and `@` does not updates model, only updates Directive scope values. – STEEL Nov 13 '15 at 04:53
  • @iwein why your fiddle code at http://jsfiddle.net/maxisam/QrCXh/ does not work with googleapi -http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js ? Your code works only if i use your cdn -https://code.angularjs.org/1.0.1/angular-1.0.1.js – MukulSharma Jul 12 '16 at 09:01
  • I see lots of good answers below, but can anyone give a pointer to the official angular documentation that answers this question? – John Henckel Dec 14 '16 at 15:48
  • @MukulSharma it's an old fiddle, feel free to fork it and suggest an edit to the question :) – iwein Jan 12 '17 at 09:49

18 Answers18

1168

Why do I have to use "{{title}}" with '@' and "title" with '='?

@ binds a local/directive scope property to the evaluated value of the DOM attribute. If you use title=title1 or title="title1", the value of DOM attribute "title" is simply the string title1. If you use title="{{title}}", the value of the DOM attribute "title" is the interpolated value of {{title}}, hence the string will be whatever parent scope property "title" is currently set to. Since attribute values are always strings, you will always end up with a string value for this property in the directive's scope when using @.

= binds a local/directive scope property to a parent scope property. So with =, you use the parent model/scope property name as the value of the DOM attribute. You can't use {{}}s with =.

With @, you can do things like title="{{title}} and then some" -- {{title}} is interpolated, then the string "and them some" is concatenated with it. The final concatenated string is what the local/directive scope property gets. (You can't do this with =, only @.)

With @, you will need to use attr.$observe('title', function(value) { ... }) if you need to use the value in your link(ing) function. E.g., if(scope.title == "...") won't work like you expect. Note that this means you can only access this attribute asynchronously. You don't need to use $observe() if you are only using the value in a template. E.g., template: '<div>{{title}}</div>'.

With =, you don't need to use $observe.

Can I also access the parent scope directly, without decorating my element with an attribute?

Yes, but only if you don't use an isolate scope. Remove this line from your directive

scope: { ... }

and then your directive will not create a new scope. It will use the parent scope. You can then access all of the parent scope properties directly.

The documentation says "Often it's desirable to pass data from the isolated scope via an expression and to the parent scope", but that seems to work fine with bidirectional binding too. Why would the expression route be better?

Yes, bidirectional binding allows the local/directive scope and the parent scope to share data. "Expression binding" allows the directive to call an expression (or function) defined by a DOM attribute -- and you can also pass data as arguments to the expression or function. So, if you don't need to share data with the parent -- you just want to call a function defined in the parent scope -- you can use the & syntax.

See also

Community
  • 1
  • 1
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • 1
    Huh, this is a really weird behavior, especially when not using interpolation and just trying to pass a string. Apparently the pull request has indeed been merged into the development builds and is in 1.1.5 and 1.2.0 RC builds. Good on them for fixing this very unintuitive behavior! – Ibrahim Sep 25 '13 at 20:36
  • 53
    Writing '@' or '=' is so much clearer then writing "eval-dom" or "parent-scope" or any other human-readable text. Good design decision. – Den Mar 03 '14 at 16:57
  • 13
    `@` ('at') copies the value of the 'ATtribute'. `=` ('equals') is equivalent to saying the key equals your expression. This, at least, is how I keep them strait. – Matt DeKrey Jun 25 '14 at 12:18
  • 1
    Are you sure that = is only for parent-scope properties? Any expression seems to work - not only parent-scope properties. – Jonathan Aquino Oct 15 '14 at 22:40
  • @JonathanAquino, well, since = sets up two-way data binding, the expression should be something assignable, and not just "any" expression. – Mark Rajcok Oct 16 '14 at 16:27
  • @MarkRajcok I don't think so - here is a CodePen showing the expression 1+1 passed into an = binding, and the result is 2: http://codepen.io/anon/pen/bDecJ – Jonathan Aquino Oct 17 '14 at 17:36
  • 5
    @JonathanAquino, yes that works, but @ would be more appropriate -- with `foo="{{1+1}}"` -- because we don't need two-way data binding here. The point I tried to make in the comment above is that we should use = only when the directive needs two-way data binding. Use @ or & otherwise. – Mark Rajcok Oct 17 '14 at 18:15
  • Awesome, but can someone explain why "$observe" is needed for "@" ??? EDIT: Nevermind, didn't see the link – Niko Bellic Sep 18 '15 at 21:59
  • Oddly if I add a '@' property to scope I can access the current value in my link function just fine. There does not appear to be a need for $observe. Could you please clarify? – TrueWill Nov 23 '15 at 21:40
  • Ah - apparently `$observe()` is for attributes that may contain curly-brace bindings. With static values it may not be necessary. – TrueWill Nov 24 '15 at 14:11
  • Would it be overreaching to ask for Angular 1.5's new "<" one-way binding type to be added to this already excellent answer? – The DIMM Reaper May 25 '16 at 18:55
551

There are a lot of great answers here, but I would like to offer my perspective on the differences between @, =, and & binding that proved useful for me.

All three bindings are ways of passing data from your parent scope to your directive's isolated scope through the element's attributes:

  1. @ binding is for passing strings. These strings support {{}} expressions for interpolated values. For example: . The interpolated expression is evaluated against directive's parent scope.

  2. = binding is for two-way model binding. The model in parent scope is linked to the model in the directive's isolated scope. Changes to one model affects the other, and vice versa.

  3. & binding is for passing a method into your directive's scope so that it can be called within your directive. The method is pre-bound to the directive's parent scope, and supports arguments. For example if the method is hello(name) in parent scope, then in order to execute the method from inside your directive, you must call $scope.hello({name:'world'})

I find that it's easier to remember these differences by referring to the scope bindings by a shorter description:

  • @ Attribute string binding
  • = Two-way model binding
  • & Callback method binding

The symbols also make it clearer as to what the scope variable represents inside of your directive's implementation:

  • @ string
  • = model
  • & method

In order of usefulness (for me anyways):

  1. =
  2. @
  3. &
jediz
  • 4,459
  • 5
  • 36
  • 41
Michael Kang
  • 52,003
  • 16
  • 103
  • 135
  • 13
    Actually, `"&"` does support arguments (or, rather, locals) of the form: `callback({foo: "some value"})`, which could then be used ``. Otherwise, good answer – New Dev Mar 20 '15 at 15:29
  • 11
    Should be accepted answer. Here is an concise article with the same information, but with added code examples: https://umur.io/angularjs-directives-using-isolated-scope-with-attributes/ – Kevin Apr 28 '15 at 15:37
  • What I gather is that "@" is evaluated before being passed to the directive, while "&" only creates a closure whose final evaluation will be triggered later inside the directive. Am I correct? – Yugo Amaryl Sep 02 '15 at 13:45
  • 4
    & is NOT "Callback method binding", it is Angular expression binding. A special but not the only example is the expression `callback(argument)`. Which is still not the same as `callback` itself. – Dmitri Zaitsev Nov 12 '15 at 04:22
  • 15
    While I loved how definitive the higher ranking answer was, I found this one made a more useful impact and after reading this one I understood the previous answer a lot more. – rbnzdave Nov 24 '15 at 18:51
  • 1
    I agree with the above comment, this answer is more clear, definitive and useful to the question. It explains with enough detail that you can go and use the information. – user3125823 Mar 08 '16 at 15:14
  • 1
    This answer is great and it most elegantly documents the scope features of $directive. However, Mark Rajcoks answer fits the original question more closely. There is not sufficient reason to unmark that one as the accepted answer. Apparently it is rewarding to read more than just the top answer on SO. All is well :) – iwein Apr 17 '16 at 11:20
  • Using
      for an ordered list :)
    – Nate Anderson Oct 27 '16 at 02:57
67

The = means bi-directional binding, so a reference to a variable to the parent scope. This means, when you change the variable in the directive, it will be changed in the parent scope as well.

@ means the variable will be copied (cloned) into the directive.

As far as I know, <pane bi-title="{{title}}" title="{{title}}">{{text}}</pane> should work too. bi-title will receive the parent scope variable value, which can be changed in the directive.

If you need to change several variables in the parent scope, you could execute a function on the parent scope from within the directive (or pass data via a service).

jediz
  • 4,459
  • 5
  • 36
  • 41
asgoth
  • 35,552
  • 12
  • 89
  • 98
  • 1
    Yes, that part I get, see the fiddle in the question. But what about the parts that are unclear? – iwein Dec 27 '12 at 07:25
  • 4
    the thing is that {{}} doesn't work with =. = isn't evaluated, but the string is taken as the property name as is. Thanks for the answer! – iwein Dec 30 '12 at 13:06
  • 1
    I don't think that = is just for variables in the parent scope. It works with any expression (e.g., 1+1). – Jonathan Aquino Oct 15 '14 at 22:42
  • 1
    @JonathanAquino you're right that it evaluates expressions. imho this is actually weird and I wouldn't use it that way. It's this kind of clever tricks that make directive scopes so hard for me to understand in the first place. – iwein May 16 '15 at 12:23
  • 1
    Am I the only one who think this answer is wrong ! '=' mean angular expect a javascript expression and will do a bidirectionnal mapping if a scope variable is passed. Whereas @ mean angular expect a String and that all. In fact, it's true that if you use @ in combinaison with {{}} you will clone the value of the variable. But it's not the definition of @ ! – Luc DUZAN May 21 '15 at 07:34
  • @LucDUZAN I would disagree: `=` does not mean Angular expects a JS expression, rather it expects an object that requires two way databinding. If the object changes in the directive, parent scope automatically receives updates to the object, and vice versa. `@` evaluates what is passed to it from the parent scope to the directive, and the output is *always* a string for the directive. One way data binding that can only be viewed as a string. `&` is utilized for passing objects or methods to the directive, but is also a one way data binding (parent scope to directive). – Mattygabe Aug 21 '15 at 18:52
39

If you would like to see more how this work with a live example. http://jsfiddle.net/juanmendez/k6chmnch/

var app = angular.module('app', []);
app.controller("myController", function ($scope) {
    $scope.title = "binding";
});
app.directive("jmFind", function () {
    return {
        replace: true,
        restrict: 'C',
        transclude: true,
        scope: {
            title1: "=",
            title2: "@"
        },
        template: "<div><p>{{title1}} {{title2}}</p></div>"
    };
});
user1338062
  • 11,939
  • 3
  • 73
  • 67
Juan Mendez
  • 2,658
  • 1
  • 27
  • 23
  • 2
    There are several examples linked in the question and top answer. What does this add? – iwein Nov 24 '14 at 09:00
  • 11
    @iwein, it adds clarity. If I could understand and assimilate full-featured examples, I would not need this site. – Tony Ennis Jan 09 '15 at 15:47
  • 3
    juan, maybe fix your typos? 'transclude' is misspelled. better yet, remove it (and everything else, like 'replace') that does not contribute directly to the problem so your solution is even simpler and clearer. +1 for the example. – Tony Ennis Jan 09 '15 at 15:49
  • thank you @AnikISlamAbhi for editing. I would like to contribute more and I am glad some find my samples helpful. That's the main purpose. – Juan Mendez Feb 10 '15 at 21:54
  • Incomplete example. In your demonstration, you are changing only the bi-directional value. Your are not even trying to change value that has isolated scope. So, it does not properly demonstrated how scope works in directives. – Sudarshan_SMD Apr 11 '18 at 06:18
  • @Sudarshan_SMD What do you expect? That is from almost four years ago, move on and adapt to Angular 5! – Juan Mendez Apr 19 '18 at 23:42
  • @JuanMendez Have already posted what I expected. My friend, sometimes you have to work on old projects. Your client won't always be willing to pay for the whole framework upgrade, when all they want is a small change in the software. – Sudarshan_SMD Apr 20 '18 at 05:36
39

@ get as string

  • This does not create any bindings whatsoever. You're simply getting the word you passed in as a string

= 2 way binding

  • changes made from the controller will be reflected in the reference held by the directive, and vice-versa

& This behaves a bit differently, because the scope gets a function that returns the object that was passed in. I'm assuming this was necessary to make it work. The fiddle should make this clear.

  • After calling this getter function, the resulting object behaves as follows:
    • if a function was passed: then the function is executed in the parent (controller) closure when called
    • if a non-function was passed in: simply get a local copy of the object that has no bindings


This fiddle should demonstrate how they work. Pay special attention to the scope functions with get... in the name to hopefully better understand what I mean about &

geg
  • 4,399
  • 4
  • 34
  • 35
38

There are three ways scope can be added in the directive:

  1. Parent scope: This is the default scope inheritance.

The directive and its parent(controller/directive inside which it lies) scope is same. So any changes made to the scope variables inside directive are reflected in the parent controller as well. You don't need to specify this as it is the default.

  1. Child scope: directive creates a child scope which inherits from the parent scope if you specify the scope variable of the directive as true.

Here, if you change the scope variables inside directive, it won't reflect in the parent scope, but if you change the property of a scope variable, that is reflected in the parent scope, as you actually modified the scope variable of the parent.

Example,

app.directive("myDirective", function(){

    return {
        restrict: "EA",
        scope: true,
        link: function(element, scope, attrs){
            scope.somvar = "new value"; //doesnot reflect in the parent scope
            scope.someObj.someProp = "new value"; //reflects as someObj is of parent, we modified that but did not override.
        }
    };
});
  1. Isolated scope: This is used when you want to create the scope that does not inherit from the controller scope.

This happens when you are creating plugins as this makes the directive generic since it can be placed in any HTML and does not gets affected by its parent scope.

Now, if you don't want any interaction with the parent scope, then you can just specify scope as an empty object. like,

scope: {} //this does not interact with the parent scope in any way

Mostly this is not the case as we need some interaction with the parent scope, so we want some of the values/ changes to pass through. For this reason, we use:

1. "@"   (  Text binding / one-way binding )
2. "="   ( Direct model binding / two-way binding )
3. "&"   ( Behaviour binding / Method binding  )

@ means that the changes from the controller scope will be reflected in the directive scope but if you modify the value in the directive scope, the controller scope variable will not get affected.

@ always expects the mapped attribute to be an expression. This is very important; because to make the “@” prefix work, we need to wrap the attribute value inside {{}}.

= is bidirectional so if you change the variable in directive scope, the controller scope variable gets affected as well

& is used to bind controller scope method so that if needed we can call it from the directive

The advantage here is that the name of the variable need not be same in controller scope and directive scope.

Example, the directive scope has a variable "dirVar" which syncs with variable "contVar" of the controller scope. This gives a lot of power and generalization to the directive as one controller can sync with variable v1 while another controller using the same directive can ask dirVar to sync with variable v2.

Below is the example of usage:

The directive and controller are:

 var app = angular.module("app", []);
 app.controller("MainCtrl", function( $scope ){
    $scope.name = "Harry";
    $scope.color = "#333333";
    $scope.reverseName = function(){
     $scope.name = $scope.name.split("").reverse().join("");
    };
    $scope.randomColor = function(){
        $scope.color = '#'+Math.floor(Math.random()*16777215).toString(16);
    };
});
app.directive("myDirective", function(){
    return {
        restrict: "EA",
        scope: {
            name: "@",
            color: "=",
            reverse: "&"
        },
        link: function(element, scope, attrs){
           //do something like
           $scope.reverse(); 
          //calling the controllers function
        }
    };
});

And the html(note the differnce for @ and =):

<div my-directive
  class="directive"
  name="{{name}}"
  reverse="reverseName()"
  color="color" >
</div>

Here is a link to the blog which describes it nicely.

Kop4lyf
  • 4,520
  • 1
  • 25
  • 31
20

Simply we can use:-

  1. @ :- for String values for one way Data binding. in one way data binding you can only pass scope value to directive

  2. = :- for object value for two way data binding. in two way data binding you can change the scope value in directive as well as in html also.

  3. & :- for methods and functions.

EDIT

In our Component definition for Angular version 1.5 And above
there are four different type of bindings:

  1. = Two-way data binding :- if we change the value,it automatically update
  2. < one way binding :- when we just want to read a parameter from a parent scope and not update it.

  3. @ this is for String Parameters

  4. & this is for Callbacks in case your component needs to output something to its parent scope

ojus kulkarni
  • 1,877
  • 3
  • 25
  • 41
14

I created a little HTML file that contains Angular code demonstrating the differences between them:

<!DOCTYPE html>
<html>
  <head>
    <title>Angular</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
  </head>
  <body ng-app="myApp">
    <div ng-controller="myCtrl as VM">
      <a my-dir
        attr1="VM.sayHi('Juan')" <!-- scope: "=" -->
        attr2="VM.sayHi('Juan')" <!-- scope: "@" -->
        attr3="VM.sayHi('Juan')" <!-- scope: "&" -->
      ></a>
    </div>
    <script>
    angular.module("myApp", [])
    .controller("myCtrl", [function(){
      var vm = this;
      vm.sayHi = function(name){
        return ("Hey there, " + name);
      }
    }])
    .directive("myDir", [function(){
      return {
        scope: {
          attr1: "=",
          attr2: "@",
          attr3: "&"
        },
        link: function(scope){
          console.log(scope.attr1);   // =, logs "Hey there, Juan"
          console.log(scope.attr2);   // @, logs "VM.sayHi('Juan')"
          console.log(scope.attr3);   // &, logs "function (a){return h(c,a)}"
          console.log(scope.attr3()); // &, logs "Hey there, Juan"
        }
      }
    }]);
    </script>
  </body>
</html>
RobertAKARobin
  • 3,933
  • 3
  • 24
  • 46
10

This question has been already beaten to death, but I'll share this anyway in case someone else out there is struggling with the horrible mess that is AngularJS scopes. This will cover =, <, @, & and ::. The full write up can be found here.


= establishes a two way binding. Changing the property in the parent will result in change in the child, and vice versa.


< establishes a one way binding, parent to child. Changing the property in the parent will result in change in the child, but changing the child property will not affect the parent property.


@ will assign to the child property the string value of the tag attribute. If the attribute contains an expression, the child property updates whenever the expression evaluates to a different string. For example:

<child-component description="The movie title is {{$ctrl.movie.title}}" />
bindings: {
    description: '@', 
}

Here, the description property in the child scope will be the current value of the expression "The movie title is {{$ctrl.movie.title}}", where movie is an object in the parent scope.


& is a bit tricky, and in fact there seems to be no compelling reason to ever use it. It allows you to evaluate an expression in the parent scope, substituting parameters with variables from the child scope. An example (plunk):

<child-component 
  foo = "myVar + $ctrl.parentVar + myOtherVar"
</child-component>
angular.module('heroApp').component('childComponent', {
  template: "<div>{{  $ctrl.parentFoo({myVar:5, myOtherVar:'xyz'})  }}</div>",
  bindings: {
    parentFoo: '&foo'
  }
});

Given parentVar=10, the expression parentFoo({myVar:5, myOtherVar:'xyz'}) will evaluate to 5 + 10 + 'xyz' and the component will render as:

<div>15xyz</div>

When would you ever want to use this convoluted functionality? & is often used by people to pass to the child scope a callback function in the parent scope. In reality, however, the same effect can be achieved by using '<' to pass the function, which is more straightforward and avoids the awkward curly braces syntax to pass parameters ({myVar:5, myOtherVar:'xyz'}). Consider:

Callback using &:

<child-component parent-foo="$ctrl.foo(bar)"/>
angular.module('heroApp').component('childComponent', {
  template: '<button ng-click="$ctrl.parentFoo({bar:'xyz'})">Call foo in parent</button>',
  bindings: {
    parentFoo: '&'
  }
});

Callback using <:

<child-component parent-foo="$ctrl.foo"/>
angular.module('heroApp').component('childComponent', {
  template: '<button ng-click="$ctrl.parentFoo('xyz')">Call foo in parent</button>',
  bindings: {
    parentFoo: '<'
  }
});

Note that objects (and arrays) are passed by reference to the child scope, not copied. What this means is that even if it's a one-way binding, you are working with the same object in both the parent and the child scope.


To see the different prefixes in action, open this plunk.

One-time binding(initialization) using ::

[Official docs]
Later versions of AngularJS introduce the option to have a one-time binding, where the child scope property is updated only once. This improves performance by eliminating the need to watch the parent property. The syntax is different from above; to declare a one-time binding, you add :: in front of the expression in the component tag:

<child-component 
  tagline = "::$ctrl.tagline">
</child-component>

This will propagate the value of tagline to the child scope without establishing a one-way or two-way binding. Note: if tagline is initially undefined in the parent scope, angular will watch it until it changes and then make a one-time update of the corresponding property in the child scope.

Summary

The table below shows how the prefixes work depending on whether the property is an object, array, string, etc.

How the various isolate scope bindings work

Mihail Kostira
  • 510
  • 7
  • 10
6

The = way is 2-way binding, which lets you to have live changes inside your directive. When someone changes that variable out of directive, you will have that changed data inside your directive, but @ way is not two-ways binding. It works like Text. You bind once, and you will have only its value.

To get it more clearly, you can use this great article:

AngularJS Directive Scope '@' and '='

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Hazarapet Tunanyan
  • 2,809
  • 26
  • 30
4

@ local scope property is used to access string values that are defined outside the directive.

= In cases where you need to create a two-way binding between the outer scope and the directive’s isolate scope you can use the = character.

& local scope property allows the consumer of a directive to pass in a function that the directive can invoke.

Kindly check the below link which gives you clear understanding with examples.I found it really very useful so thought of sharing it.

http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-2-isolate-scope

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Raphael
  • 1,738
  • 2
  • 27
  • 47
3

Even when the scope is local, as in your example, you may access the parent scope through the property $parent. Assume in the code below, that title is defined on the parent scope. You may then access title as $parent.title:

link : function(scope) { console.log(scope.$parent.title) },
template : "the parent has the title {{$parent.title}}"

However in most cases the same effect is better obtained using attributes.

An example of where I found the "&" notation, which is used "to pass data from the isolated scope via an expression and to the parent scope", useful (and a two-way databinding could not be used) was in a directive for rendering a special datastructure inside an ng-repeat.

<render data = "record" deleteFunction = "dataList.splice($index,1)" ng-repeat = "record in dataList" > </render>

One part of the rendering was a delete button and here it was useful to attach a deletefunction from the outside scope via &. Inside the render-directive it looks like

scope : { data = "=", deleteFunction = "&"},
template : "... <button ng-click = "deleteFunction()"></button>"

2-way databinding i.e. data = "=" can not be used as the delete function would run on every $digest cycle, which is not good, as the record is then immediately deleted and never rendered.

Mark Schultheiss
  • 32,614
  • 12
  • 69
  • 100
3

I implemented all the possible options in a fiddle.

It deals with all the options:

scope:{
    name:'&'
},

scope:{
    name:'='
},

scope:{
    name:'@'
},

scope:{

},

scope:true,

https://jsfiddle.net/rishulmatta/v7xf2ujm

iwein
  • 25,788
  • 10
  • 70
  • 111
Rishul Matta
  • 3,383
  • 5
  • 23
  • 29
3

the main difference between them is just

@ Attribute string binding
= Two-way model binding
& Callback method binding
Ashish Kamble
  • 2,555
  • 3
  • 21
  • 29
1

@ and = see other answers.

One gotcha about &
TL;DR;
& gets expression (not only function like in examples in other answers) from a parent, and sets it as a function in the directive, that calls the expression. And this function has the ability to replace any variable (even function name) of expression, by passing an object with the variables.

explained
& is an expression reference, that means if you pass something like <myDirective expr="x==y"></myDirective>
in the directive this expr will be a function, that calls the expression, like:
function expr(){return x == y}.
so in directive's html <button ng-click="expr()"></button> will call the expression. In js of the directive just $scope.expr() will call the expression too.
The expression will be called with $scope.x and $scope.y of the parent.
You have the ability to override the parameters!
If you set them by call, e.g. <button ng-click="expr({x:5})"></button>
then the expression will be called with your parameter x and parent's parameter y.
You can override both.
Now you know, why <button ng-click="functionFromParent({x:5})"></button> works.
Because it just calls the expression of parent (e.g. <myDirective functionFromParent="function1(x)"></myDirective>) and replaces possible values with your specified parameters, in this case x.
it could be:
<myDirective functionFromParent="function1(x) + 5"></myDirective>
or
<myDirective functionFromParent="function1(x) + z"></myDirective>
with child call:
<button ng-click="functionFromParent({x:5, z: 4})"></button>.
or even with function replacement:
<button ng-click="functionFromParent({function1: myfn, x:5, z: 4})"></button>.

it just an expression, does not matter if it is a function, or many functions, or just comparison. And you can replace any variable of this expression.

Examples:
directive template vs called code:
parent has defined $scope.x, $scope.y:
parent template: <myDirective expr="x==y"></myDirective>
<button ng-click="expr()"></button> calls $scope.x==$scope.y
<button ng-click="expr({x: 5})"></button> calls 5 == $scope.y
<button ng-click="expr({x:5, y:6})"></button> calls 5 == 6

parent has defined $scope.function1, $scope.x, $scope.y:
parent template: <myDirective expr="function1(x) + y"></myDirective>

<button ng-click="expr()"></button> calls $scope.function1($scope.x) + $scope.y
<button ng-click="expr({x: 5})"></button> calls $scope.function1(5) + $scope.y
<button ng-click="expr({x:5, y:6})"></button> calls $scope.function1(5) + 6
directive has $scope.myFn as function:
<button ng-click="expr({function1: myFn, x:5, y:6})"></button> calls $scope.myFn(5) + 6

ya_dimon
  • 3,483
  • 3
  • 31
  • 42
0

Why do I have to use "{{title}}" with '@' and "title" with '='?

When you use {{title}} , only the parent scope value will be passed to directive view and evaluated. This is limited to one way, meaning that change will not be reflected in parent scope. You can use '=' when you want to reflect the changes done in child directive to parent scope also. This is two way.

Can I also access the parent scope directly, without decorating my element with an attribute?

When directive has scope attribute in it ( scope : {} ), then you no longer will be able to access parent scope directly. But still it is possible to access it via scope.$parent etc. If you remove scope from directive, it can be accessed directly.

The documentation says "Often it's desirable to pass data from the isolated scope via an expression and to the parent scope", but that seems to work fine with bidirectional binding too. Why would the expression route be better?

It depends based on context. If you want to call an expression or function with data, you use & and if you want share data , you can use biderectional way using '='

You can find the differences between multiple ways of passing data to directive at below link:

AngularJS – Isolated Scopes – @ vs = vs &

http://www.codeforeach.com/angularjs/angularjs-isolated-scopes-vs-vs

Prashanth
  • 914
  • 10
  • 7
0

@ Attribute string binding (one way) = Two-way model binding & Callback method binding

Jatin Patel
  • 57
  • 1
  • 4
0

@ binds a local/directive scope property to the evaluated value of the DOM attribute. = binds a local/directive scope property to a parent scope property. & binding is for passing a method into your directive's scope so that it can be called within your directive.

@ Attribute string binding = Two-way model binding & Callback method binding

Ashish Kamble
  • 2,555
  • 3
  • 21
  • 29