I have a question regarding scopes in directives of angularjs. Please have a look at the following code:
HTML:
<div ng-controller="MyCtrl">
<!-- 1. works: -->
<pre>{{controllerItems}}</pre>
<my-list attr-items="controllerItems">
<!-- 3. works not: -->
<pre>{{directiveItems}}</pre>
<!-- 4. works: -->
<pre>{{controllerItems}}</pre>
</my-list>
</div>
JS:
angular.module('myapp', [])
.controller('MyCtrl', function($scope) {
$scope.controllerItems = [
'A', 'B', 'C', 'D'
];
})
.directive('myList', function () {
return {
restrict: 'E',
transclude : true,
template : '<!-- 2. works: --><pre>{{directiveItems}}</pre><div ng-transclude></div>',
scope : {
directiveItems : '=attrItems'
},
link: function (scope, element, attrs, ctrl) {
//console.log(scope);
}
}
});
What I tried to do is to create an own scope for a directive and all of its children. I created a new scope for the directive with scope : { } and expected, that all children of the directive can use it. But what I get is, that 3. does not know directiveItems and in 4. the parent scope still exists.
My question: What can I do to create a separate scope with a directive, which is also available for all child-elements like {{ }} oder other default and custom elements?
You can also find the code here: http://plnkr.co/edit/kKtGdNt8Jq09zabwVoJo?p=preview
Thanks for your help!
The ng-transclude directive used in your template binds the transcluded content to a new scope that prototypically inherits the parent scope (through scope.$new()). This new scope can therefore see controllerItems and the isolate scope variable directiveItems is not available.
If you want to bind to transcluded content to the isolate scope, use the transcludeFn passed to the link function and pass it the isolate scope. Note that when you do this, controllerItems will no longer be available:
.directive('myList', function () {
return {
restrict: 'E',
transclude : true,
template : '<pre>{{directiveItems}}</pre>',
scope : {
directiveItems : '=attrItems'
},
link: function (scope, element, attrs, ctrl, transcludeFn) {
//Bind the transcluded content to the isolated scope
transcludeFn(scope, function (clone) {
element.after(clone);
}
}
}
});
http://jsfiddle.net/vjxn7qyc/1/
Use this sparingly as an isolate scope is supposed to do just that, isolate itself from the outer code. When you transclude content that claims to know the isolate scope, you are bending the rules :).