Edit:
There is a functional example in this plunker:
http://plnkr.co/edit/GFQGP0q3o9RjLAlRANPS?p=preview
Outer scope has $scope.name = 'Donald'
All directives are declared as:
<directive-name binding="name">
This is a multi-part question. Im trying to gain a better understanding of isolated scopes that has a watch or a binding to an outer scope variable.
With a non-isolated scope directive everything works as it should:
// [WORKS]
.directive('noScopeWithWatch', function(){
return {
restrict: 'E',
link: function(scope, lElement, attrs) {
scope.$watch(attrs.binding, function(name){
lElement.text('Hello ' + name);
});
}
};
})
// returns Hello Donald
The confusing part is when I try to isolate the scope and keep the binding. So what Im asking for is a clarification on why some of the following examples work, while and others do not.
If I just add the scope isolation with a 'normal' binding it fails:
// 1. [FAILS]
.directive('scopeWithWatch', function(){
return {
restrict: 'E',
link: function(scope, lElement, attrs) {
scope.$watch(attrs.binding, function(name){
lElement.text('Hello ' + name);
});
},
scope: { // new content
binding: '=' // new content
} // new content
};
})
// returns Hello undefined
However, using the binding variable in the watch as a string makes it work:
// 2. [WORKS]
.directive('scopeWithWatchString', function(){
return {
restrict: 'E',
link: function(scope, lElement, attrs) {
scope.$watch('binding', function(b){ // new content
lElement.text('Hello ' + b);
});
},
scope: {
binding: '='
}
};
})
// returns Hello Donald
While using the binding variable as an object fails misribly:
// 3. [FAILS]
.directive('scopeWithWatchObject', function(){
return {
restrict: 'E',
link: function(scope, lElement, attrs) {
scope.$watch(binding, function(b){ // new content
lElement.text('Hello ' + b);
});
},
scope: {
binding: '='
}
};
})
// Does not work at all
// Console output - ReferenceError: binding is not defined
Trying to reference the binding variable insinde the isolated scope does not work either, but at least does not cause an exception :
// 4. [FAILS]
.directive('scopeWithWatchScopeObject', function(){
return {
restrict: 'E',
link: function(scope, lElement, attrs) {
scope.$watch(scope.binding, function(b){ // new content
lElement.text('Hello ' + b);
});
},
scope: {
binding: '='
}
};
})
// returns Hello undefined
It turns out that using the binding variable in mustaches in a template works:
// 5. [WORKS]
.directive('scopeWithTemplate', function(){
return {
restrict: 'E',
template: 'Hello {{binding}}', // new content and linker removed
scope: {
binding: '='
}
};
})
// returns Hello Donald
But trying to use them as mustaches in the linker does not.
// 6. [FAILS]
.directive('scopeWithWatchStringUsingMustashes', function(){
return {
restrict: 'E',
link: function(scope, lElement, attrs) { // new content
scope.$watch('binding', function(){ // new content
lElement.text('Hello {{binding}}'); // new content
}); // new content
}, // new content
scope: {
binding: '='
}
};
})
// returns Hello {{binding}}
Here is the plunker:
http://plnkr.co/edit/GFQGP0q3o9RjLAlRANPS?p=preview (Im currently at version 78, please fork if you want to use it in your answer.)
Could someone please explain to me why some examples work while others do not.
There is a simple answer to this, which applies to all the examples here. The Angular documentation on $compile explains this, but it is easy to misunderstand. The entire purpose of an isolated scope is to create a scope that is consumed ONLY by the directive that declares it. In order to do so, a new variable is created which stores the value as an alias of the parent scope.
There are 3 major definition types: @, =, &
@ or @attr - bind a local scope property to the value of DOM attribute. The result is always a string since DOM attributes are strings.
= or =attr - set up bi-directional binding between a local scope property and the parent scope property of name defined via the value of the attr attribute.
& or &attr - provides a way to execute an expression in the context of the parent scope.
The only difference between @ and = is bi-directional support. The = definition will still return a string result.
So, what you have, in order, is:
binding='name' is matched to binding: '=' and 'binding' is accessable as an alias in the isolated scope.The 'isolate' scope differs from normal scope in that it does not prototypically inherit from the parent scope. This is useful when creating reusable components, which should not accidentally read or modify data in the parent scope.
$compile automatically.lElement.text is simply that, text. using an expression within a text assignment requires an additional manual compile step before the text is sent to the dom, else the {{}} expression is treated as plain text.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With