The problem I have can be see at http://jsfiddle.net/miketheanimal/2CcYp/13/ This strips down my problem to a minimum.
I have a controller "main", a directive "outer" which transclude's, and a directive "inner" which doesn't. Each directive has an isolate scope and a controller. The main and the directive controllers set $scope._name = '...' so I can tell them apart.
var module = angular.module('miketa', []);
function main ($scope) {
$scope._name = 'main' ;
} ;
module.directive('outer', function() {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {},
template: '<div><div ng-transclude></div></div>',
controller: [ '$scope', function($scope) {
$scope._name = 'outer' ;
document.getElementById('opn').innerHTML = $scope.$parent._name ;
}]}});
module.directive('inner', function() {
return {
restrict: 'E',
replace: true,
scope: {},
template: '<div></div>',
controller: [ '$scope', function($scope) {
$scope._name = 'inner' ;
document.getElementById('ipn').innerHTML = $scope.$parent._name ;
}]}});
The HTML nests these as main -> outer -> inner. The controller functions in the directives copy their parent scope name (ie., *$scope.$parent._name) into the rendered HTML (apologies for manipulating the DOM directly, it was the easiest way to display the names!).
I would expect outer to show the name from the controller (ie., "main") which is does, and I'd expect inner to show the name from outer (ie., "outer"), which is doesn't, rather it shows "main" as well.
The problem actually manifests itself since in the real code, I'd like to bind between the inner and outer scopes, but inner ends up binding to the main scope.
In fact it's not a bug, it's the desired behavior. From the docs on the $compile
service:
In a typical setup the widget creates an isolate scope, but the transclusion is not a child, but a sibling of the isolate scope. This makes it possible for the widget to have private state, and the transclusion to be bound to the parent (pre-isolate) scope.
See also: Why ng-transclude's scope is not a child of its directive's scope - if the directive has an isolated scope?
If you really need to get it work forget ng-transclude
and do:
var module = angular.module('miketa', []);
function main($scope) {
$scope._name = 'main';
};
module.directive('outer', function () {
return {
restrict: 'E',
replace: true,
scope: {},
template: '<div><inner></inner></div>',
controller: ['$scope', function ($scope) {
$scope._name = 'outer';
document.getElementById('opn').innerHTML = $scope.$parent._name;
}]
}
});
module.directive('inner', function () {
return {
restrict: 'E',
replace: true,
scope: {},
template: '<div></div>',
controller: ['$scope', function ($scope) {
$scope._name = 'inner';
document.getElementById('ipn').innerHTML = $scope.$parent._name;
}]
}
});
And voila! It works.
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