What is the difference between '#' and '=' in directive scope in AngularJS? - angularjs

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/

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
Lukas's isolated scope blog post (covers #, =, &)
dnc253's explanation of # and =
my blog-like answer about scopes -- the directives section (way at the bottom, just before the Summary section) has a picture of an isolate scope and its parent scope -- the directive scope uses # for one property and = for another
What is the difference between & vs # and = in angularJS

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:
# binding is for passing strings.
These strings support {{}} expressions for interpolated values.
For example:
. The interpolated expression is evaluated against
directive's parent scope.
= 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.
& 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):
=
#
&

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).

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>"
};
});

# 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 &

There are three ways scope can be added in the directive:
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.
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.
}
};
});
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.

Simply we can use:-
# :- for String values for one way Data binding. in one way data binding you can only pass scope value to directive
= :- 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.
& :- for methods and functions.
EDIT
In our Component definition for Angular version 1.5 And above
there are four different type of bindings:
= Two-way data binding :- if we change the value,it automatically update
< one way binding :- when we just want to read a parameter from a parent scope and not update it.
# this is for String Parameters
& this is for Callbacks in case your component needs to output something to its parent scope

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>

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.

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 '='

# 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

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.

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

the main difference between them is just
# Attribute string binding
= Two-way model binding
& Callback method binding

# 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

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

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

# 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

Related

Multiple of same component on page overwrites itself

I have a directive twice on a page, but it keeps overwriting itself.
Meaning, the dialogId gets overwritten by the next instance of example-dialog in the template instead of keeping their own dialogIds.
angular.module('directives')
.directive('exampleDialog', ["$rootScope", "$timeout", "ngDialog", "$compile", '$templateRequest', function ($rootScope, $timeout, ngDialog, $compile, $templateRequest) {
return {
templateUrl: "/dialog.component.html",
transclude: {
button: '?dialogButton',
title: '?dialogTitle',
body: '?dialogBody',
footer: '?dialogFooter'
},
replace: true,
link: function (scope, el, attrs, ctrl, transclude) {
var dialogId = scope.blah.id; // gets overwritten - so when scope.open() gets called, the last instance ID gets used for both
scope.open = function(){
console.log(dialogId) // prints the same for both directives instead of the unique dialogId.
}
},
controller: function ($scope) {
}
}
}]);
With the following HTML:
<example-dialog>
<dialog-button>
ExampleButton1
</dialog-button>
<dialog-title ng-non-bindable>Title1</dialog-title>
<dialog-body ng-non-bindable>
<div ng-include="'template1.tpl.html'"></div>
</dialog-body>
<dialog-footer ng-non-bindable>
</dialog-footer>
</example-dialog>
<example-dialog>
<dialog-button>
ExampleButton2
</dialog-button>
<dialog-title ng-non-bindable>Title2</dialog-title>
<dialog-body ng-non-bindable>
<div ng-include="'template2.tpl.html'"></div>
</dialog-body>
<dialog-footer ng-non-bindable>
</dialog-footer>
</example-dialog>
How can I get them to save their own references while still inheriting their parents' scope?
EDIT
Someone recommended that I use scope: true which is supposed to create classic prototypal inheritance.
However, When I try that - open() from the <dialog-button> tansclusion point doesn't work now, along with any other bindings in the template.
You should isolate the scope of your directive. by adding scope:{} in your return statement.
By doing this your directive will create its own controlled scope and you will not be able to get any value from your parent scope(Basically no conflicts from parent scope).. To access value from parent controller/scope you will need to pass them explicitly.
To complet the previous answer, you can see in angular official doc ( here ) that :
The scope property can be false, true, or an object:
false (default): No scope will be created for the directive. The
directive will use its parent's scope.
true: A new child scope that prototypically inherits from its parent
will be created for the directive's element. If multiple directives on
the same element request a new scope, only one new scope is created.
{...} (an object hash): A new "isolate" scope is created for the
directive's template. The 'isolate' scope differs from normal scope in
that it does not prototypically inherit from its parent scope. This is
useful when creating reusable components, which should not
accidentally read or modify data in the parent scope. Note that an
isolate scope directive without a template or templateUrl will not
apply the isolate scope to its children elements.
Edit Like #itamar mentioned in his comment :
When I use scope:true it seems that it does keep the id in the directive (checked with going to the dom element and printing the scope). However, open() from the tansclusion point doesn't work now, along with any other bindings in the template.
The answer (from angularjs doc ) is :
The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the directive's element. These local properties are useful for aliasing values for templates. The keys in the object hash map to the name of the property on the isolate scope; the values define how the property is bound to the parent scope, via matching attributes on the directive's element:
# or #attr - bind a local scope property to the value of DOM attribute.
= or =attr - set up a bidirectional binding between a local scope property and an expression passed via the attribute attr. The expression is evaluated in the context of the parent scope.
< or < attr - set up a one-way (one-directional) binding between a local scope property and an expression passed via the attribute attr. The expression is evaluated in the context of the parent scope. If no attr name is specified then the attribute name is assumed to be the same as the local name.
& or &attr - provides a way to execute an expression in the context of the parent scope. If no attr name is specified then the attribute name is assumed to be the same as the local name.

# = and & why need to use in AngularJs? [duplicate]

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/
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
Lukas's isolated scope blog post (covers #, =, &)
dnc253's explanation of # and =
my blog-like answer about scopes -- the directives section (way at the bottom, just before the Summary section) has a picture of an isolate scope and its parent scope -- the directive scope uses # for one property and = for another
What is the difference between & vs # and = in angularJS
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:
# binding is for passing strings.
These strings support {{}} expressions for interpolated values.
For example:
. The interpolated expression is evaluated against
directive's parent scope.
= 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.
& 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):
=
#
&
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).
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>"
};
});
# 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 &
There are three ways scope can be added in the directive:
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.
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.
}
};
});
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.
Simply we can use:-
# :- for String values for one way Data binding. in one way data binding you can only pass scope value to directive
= :- 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.
& :- for methods and functions.
EDIT
In our Component definition for Angular version 1.5 And above
there are four different type of bindings:
= Two-way data binding :- if we change the value,it automatically update
< one way binding :- when we just want to read a parameter from a parent scope and not update it.
# this is for String Parameters
& this is for Callbacks in case your component needs to output something to its parent scope
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>
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.
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 '='
# 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
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.
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
the main difference between them is just
# Attribute string binding
= Two-way model binding
& Callback method binding
# 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
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
# Attribute string binding (one way)
= Two-way model binding
& Callback method binding
# 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

Angular directive with scope : # not working

Here is my directive code which works fine:
.directive('myGrid',function(){
return {
restrict:'E',
scope:{
info:'=info'
},
templateUrl : '/directiveGrid.html'
}
})
Here is a codepen demo
But if I change the scope like :
.directive('myGrid',function(){
return {
restrict:'E',
scope:{
info:'#info'
},
templateUrl : '/directiveGrid.html'
}
})
It doesn't work. Here is the second demo
The problem is when you have use # for isolate scope binding, it passes the value from attribute to directive. Basically while passing value using # it stringify that value and before passing it to directive. So value went to directive is not in a JSON format, it get stringified before reach to directive(data type changed to string).
If you do {{info}} you will see the result(which is nothing but string). It has been converted to string thats why you can't see ng-repear working
Preferred approach would be use =, that will do two things
Two way binding
It preserves data-type of value when value passes to directive.
Here's some explanation:
# binds a local/directive scope property to the evaluated value of the DOM attribute. 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 #.
# allows a value defined on the directive attribute to be passed to the directive's isolate scope.
= 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 =.
= sets up a two-way binding expression between the directive's isolate scope and the parent scope. Changes in the child scope and propagated to the parent and vice-versa. Think of = as a combination of # and &. Screencast on = is here: https://egghead.io/lessons/angularjs-isolate-scope-two-way-binding
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.

Proper way to pass functions to directive for execution in link

I know we usually pass functions to directives via an isolated scope:
.directive('myComponent', function () {
return {
scope:{
foo: '&'
}
};
})
And then in the template we can call this function like such:
<button class="btn" ng-click="foo({ myVal: value })">Submit</button>
Where myVal is the name of the parameter that function foo in the parent scope takes.
Now if I intend to use this from the link function instead of template, I will have to call it with: scope.foo()(value), since scope.foo serves as a wrapper of the original function. This seems a bit tedious to me.
If I pass the function to the myComponent directive using =:
.directive('myComponent', function () {
return {
scope:{
foo: '='
}
};
})
Then I will be able to just use scope.foo(value) from my link function. So is this a valid use case to use 2-way binding on functions, or am I doing some sort of hack that I shouldn't be doing?
Here is why I downvoted the answer.
First, you should never use '=' to pass function references to directives.
'=' creates two watches and uses them to ensure that both the directive scope and the parent scope references are the same (two-way binding). It is a really bad idea to allow a directive to change the definition of a function in your parent scope, which is what happens when you use this type of binding. Also, watches should be minimized - while it will work, the two extra $watches are unnecessary. So it is not fine - part of the down vote was for suggesting that it was.
Second - the answer misrepresents what '&' does. & is not a "one way binding". It gets that misnomer simply because, unlike '=', it does not create any $watches and changing the value of the property in the directive scope does not propagate to the parent.
According to the docs:
& or &attr - provides a way to execute an expression in the context of
the parent scope
When you use & in a directive, it generates a function that returns the value of the expression evaluated against the parent scope. The expression does not have to be a function call. It can be any valid angular expression. In addition, this generated function takes an object argument that can override the value of any local variable found in the expression.
To extend the OP's example, suppose the parent uses this directive in the following way:
<my-component foo="go()">
In the directive (template or link function), if you call
foo({myVal: 42});
What you are doing is evaluating the expression "go()", which happens to call the function "go" on the parent scope, passing no arguments.
Alternatively,
<my-component foo="go(value)">
You are evaluating the expression "go(value)" on the parent scope, which will is basically calling $parent.go($parent.value)"
<my-component foo="go(myVal)">
You are evaluating the expression "go(myVal)", but before the expression is evaluated, myVal will be replaced with 42, so the evaluated expression will be "go(42)".
<my-component foo="myVal + value + go()">
In this case, $scope.foo({myVal: 42}) will return the result of:
42 + $parent.value + $parent.go()
Essentially, this pattern allows the directive to "inject" variables that the consumer of the directive can optionally use in the foo expression.
You could do this:
<my-component foo="go">
and in the directive:
$scope.foo()(42)
$scope.foo() will evaluate the expression "go", which will return a reference to the $parent.go function. It will then call it as $parent.go(42). The downside to this pattern is that you will get an error if the expression does not evaluate to a function.
The final reason for the down vote was the assertion that the ng-event directives use &. This isn't the case. None of the built in directives create isolated scopes with:
scope:{
}
The implementation of '&foo' is (simplified for clarity), boils down to:
$scope.foo = function(locals) {
return $parse(attr.foo)($scope.$parent, locals);
}
The implementation of ng-click is similar, but (also simplified):
link: function(scope, elem, attr) {
elem.on('click', function(evt) {
$parse(attr.ngClick)(scope, {
$event: evt
}
});
}
So the key to remember is that when you use '&', you are not passing a function - you are passing an expression. The directive can get the result of this expression at any time by invoking the generated function.
Two-way binding to pass a function is fine as long as your function will always take the same parameters in the same order. But also useless for that purpose.
The one-way binding is more efficient and allows to call a function with any parameter and in any order, and offer more visibility in the HTML. For instance we could not imagine ngClick to be a two-way binding: sometimes you want something like <div ng-click="doStuff(var1)"> up to more complex things such as
<div ng-click="doStuff('hardcoded', var1+4); var2 && doAlso(var2)">
See: you can manipulate the parameters directly from the HTML.
Now I feel like you misunderstood how to use one-way bindings. If you indeed define onFoo: '&' in your directive, then from the link function you should do for instance:
// assume bar is already in your scope
scope.bar = "yo";
// Now you can call foo like this
scope.onFoo( {extra: 42} );
So in your HTML you could use
<div on-foo="doSomething(bar, extra)">
Note that you have access to not only all the properties of the directive isolated scope (bar), but also the extra "locals" added at the moment of the call (extra).
Your notation like scope.foo()(value) looks like a hack to me, that is not the itended way to use one-way bindings.
Note: one-way bindings are typically used with some "event" functions such as when-drop, on-leave, ng-click, when-it-is-loaded, etc.

Need some examples of binding attributes in custom AngularJS tags

I am attempting to create a custom tag similar to the following:
<mytag type="Big" />
where type is an attribute that gets bound to the component. in such a way that it sets the text in a label, as shown below:
<label>{{type}}</label>
... (other components)...
As the documentation says, I have a controller that sets a default type:
$scope.type = "Small";
so that if I use my tag without the attribute type still gets set.
I am attempting to do binding using a directive:
angular.module('TestPage',[])
.directive('mytag',function() {
return {
restrict: 'E',
templateUrl: 'component.html',
scope: {
type: '='
}
}
});
Note that I do have the appropriate ng-app settings in my component template (ng-app="TestPage").
My problem is that the binding to type does not appear to be actually binding anything.
I have read the documentation about how to bind a variable to components using directive. According to the documentation, you can do such bindings inside a scope. Scopes apparently can contain an "object-hash" (whatever that is!) which creates something called an "isolate scope" (???). Such scopes can represent "local properties" in the following ways:
# or #attr - bind a local scope property to the DOM attribute. The result is always a string
since DOM attributes are strings. If no attr name is specified then the local name and
attribute name are same. Given and widget definition of scope: { localName:'#myAttr' }, then widget scope property localName will reflect the interpolated value of hello {{name}}. As the name attribute changes so will the localName property on the widget scope. The name is read from the parent scope (not component scope).
Huh??? What has all this to do with the proper syntax for binding?
= or =expression - set up bi-directional binding between a local scope property and the parent
scope property. If no attr name is specified then the local name and attribute name are same.
Given and widget definition of scope: { localModel:'=myAttr' }, then widget scope property localName will reflect the value of parentModel on the parent scope. Any changes to parentModel will be reflected in localModel and any changes in localModel will reflect in parentModel.
Excuse me? What is being said here???
& or &attr - provides a way to execute an expression in the context of the parent scope. If no
attr name is specified then the local name and attribute name are same. Given
and widget definition of scope: { localFn:'increment()' },
then isolate scope property localFn will point to a function wrapper for the increment() expression. Often it's desirable to pass data from the isolate scope via an expression and to the parent scope, this can be done by passing a map of local variable names and values into the expression wrapper fn. For example, if the expression is increment(amount) then we can specify the amount value by calling the localFn as localFn({amount: 22}).
Now I'm totally confused! You have widget tags and some kind of related function that I have to write iin order to do the bind??? All I want is to bind a value to a label tag!
I have copied the above text from the documentation (http://docs.angularjs.org/guide/directive) to make a point: that this doco reads like the old UNIX documentation: really useful to those who already know the system, but not so helpful to beginners who are trying to develop real expertise. With all the tutorials that show how to do simple tasks in AngularJS (great for toy apps but not so good for the kinds of client- side applications I want to build), why aren't there any for the more advanced stuff???
Okay, time for me to be more constructive.
Can someone please provide some nice, simple examples of how to do the various bindings that this documentation is trying so hard to describe??? Examples that show the proper syntax for these scope statements and descriptions (in plain English) of exactly how they go back to the attribute being added to the custom tag???
Thank you for your patience and thanks in advance for any assistance.
I struggled a bit with this documentation too when first getting into angular, but I will make an attempt try to clarify things for you. First, when using this scope property, it creates an "isolated scope." All this means is that it won't inherit any properties from parent scopes, and so you don't have to worry about any collisions within the scope.
Now, the '#' notation means that the evaluated value in the attribute will automatically get bound into your scope for the directive. So, <my-directive foo="bar" /> would end up with the scope having a property called foo that holds the string "bar". You could also do something like <my-directive foo="{{bar}}" And then the evaluated value of {{bar}} will be bound to the scope. Since attributes are always strings, you will always end up with a string for this property in the scope when using this notation.
The '=' notation basically provides a mechanism for passing an object into your directive. It always pulls this from the parent scope of the directive, so this attribute will never have the {{}}. So, if you have <my-directive foo="bar" /> it will bind whatever is in $scope.bar into your directive in the foo property of your directive's scope. Any change's you make to foo within your scope will be refelected in bar in the parent scope, and vice versa.
I haven't used the '&' notation nearly as much as the other too, so I don't know it as well as those two. From what I understand, it allows you to evaluate expressions from the context of the parent scope. So if you have something like <my-directive foo="doStuff()" />, whenever you call scope.foo() within your directive, it will call the doStuff function in the directive's parent scope. I'm sure there's a lot more you can do with this, but I'm not as familiar with it all. Maybe someone else can explain this one in more detail.
If just the symbol is set in the scope, it will use the same name as the attribute to bind to the directives scope. For example:
scope: {
foo1: '#',
foo2: '=',
foo3: '&'
}
When including the directive, there would need to be the attributes foo1, foo2, and foo3. If you want a property in your scope different than the attribute name, you can specify that after the symbol. So, the example above would be
scope: {
foo1: '#bar1',
foo2: '=bar2',
foo3: '&bar3'
}
When including the directive, there would need to be the attributes bar1, bar2, and bar3, and these would get bound in the scope under properties foo1, foo2, and foo3 respectively.
I hope this helps. Feel free to ask questions with which I can clarify my answer.
Youre pretty close..
app.directive('mytag',function() {
return {
restrict: 'E',
template: '<div>' +
'<input ng-model="controltype"/>' +
'<button ng-click="controlfunc()">Parent Func</button>' +
'<p>{{controlval}}</p>' +
'</div>',
scope: {
/* make typeattribute="whatever" bind two-ways (=)
$scope.whatever from the parent to $scope.controltype
on this directive's scope */
controltype: '=typeattribute',
/* reference a function from the parent through
funcattribute="somefunc()" and stick it our
directive's scope in $scope.controlfunc */
controlfunc: '&funcattribute',
/* pass a string value into the directive */
controlval: '#valattribute'
},
controller: function($scope) {
}
};
});
<div ng-controller="ParentCtrl">
<!-- your directive -->
<mytag typeattribute="parenttype" funcattribute="parentFn()" valattribute="Wee, I'm a value"></mytag>
<!-- write out your scope value -->
{{parenttype}}
</div>
app.controller('ParentCtrl', function($scope){
$scope.parenttype = 'FOO';
$scope.parentFn = function() {
$scope.parenttype += '!!!!';
}
});
The magic is mostly in the scope: declaration in your directive definition. having any scope: {} in there will "isolate" the scope from the parent, meaning it gets it's own scope... without that, it would use the parent's scope. The rest of the magic is in the scope's properties: scope: { 'internalScopeProperty' : '=externalAttributeName' }... where the = represents a two way binding scenario. If you change that = to a # you'll see it just allows you to pass a string as an attribute to the directive. The & is for executing functions from the parent scope's context.
I hope that helps.
EDIT: Here is a working PLNKR

Resources