I would like to access a parent directive's scope, but I can't seem to get the right combination of settings. Is this possible and is it the right approach?
I really want to avoid putting something like SOME_CONST (which would help me make DOM updates through control flow) in MyCtrl
<div ng-controller="MyCtrl">
<parent>
<child></child>
</parent>
</div>
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.obj = {prop:'foo'};
}
myApp.directive('parent', function() {
return {
scope: true,
transclude: true,
restrict: 'EA',
template: '<div ng-transclude><h1>I\'m parent {{obj.prop}}<h1></div>',
link: function(scope, elem, attrs) {
scope.SOME_CONST = 'someConst';
}
}
});
myApp.directive('child', function() {
return {
restrict: 'EA',
template: '<h1>I\'m child.... I want to access my parent\'s stuff, but I can\'t. I can access MyCtrlScope though, see <b>{{obj.prop}}</b></h1> how can I access the <b>SOME_CONST</b> value in my parent\'s link function? is this even a good idea? {{SOME_CONST}}. I really don\'t want to put everything inside the MyCtrl',
}
});
Please see this fiddle
Thanks
You can still access the parent scope using $parent , but this is not normally recommended. Instead, you should specify which parent scope properties (and/or function) the directive needs via additional attributes on the same element where the directive is used, using the = , @ , and & notation.
In a nutshell: You cannot access child scopes from a parent scope. Your solutions: Define properties in parents and access them from children (read the link above) Use a service to share state.
You just create a myVar variable in your controller and pass it to the directive using my-var attribute. Since you are using two way binding, any changes made to myVar by the directive are available in your controller.
The directive scope uses prefixes to achieve that. Using prefixes helps establish a two-way or one-way binding between parent and directive scopes, and also make calls to parent scope methods. To access any data in the parent scope requires passing the data at two places – the directive scope and the directive tag.
With transclude: true
and scope: true
, the parent
directive creates two new scopes:
Scope 004 is a result of scope: true
, and scope 005 is a result of transclude: true
. Since the child
directive does not create a new scope, it uses transcluded scope 005. As you can see from the diagram there is no path from scope 005 to scope 004 (except via private property $$prevSibling, which goes in the opposite direction of $$nextSibling -- but don't use those.)
@joakimbl's solution is probably best here, although I think it is more common to define an API on the parent directive's controller, rather than defining properties on this
:
controller: function($scope) { $scope.SOME_CONST = 'someConst'; this.getConst = function() { return $scope.SOME_CONST; } }
Then in the child
directive:
link:function(scope,element,attrs,parentCtrl){ scope.SOME_CONST = parentCtrl.getConst(); },
This is how the tabs
and pane
directives work on Angular's home page ("Create Components" example).
Normally the way you access a parent scope variable in a directive is through bi-directional binding (scope:{model:'=model'}
- see the angular guide on directives) in the directive configuration), but since you're using transclusion this is not so straight forward. If the child directive will always be a child of the parent directive you can however configure it to require the parent, and then get access to the parent controller in the child link function:
myApp.directive('parent', function() {
return {
scope: true,
transclude: true,
restrict: 'EA',
template: '<div ng-transclude><h1>I\'m parent {{obj.prop}}<h1></div>',
controller: function($scope) {
$scope.SOME_CONST = 'someConst';
this.SOME_CONST = $scope.SOME_CONST;
}
}
});
myApp.directive('child', function() {
return {
restrict: 'EA',
require:'^parent',
scope:true,
link:function(scope,element,attrs,parentCtrl){
scope.SOME_CONST = parentCtrl.SOME_CONST;
},
template: '<h1>I\'m child.... I want to access my parent\'s stuff, but I can\'t. I can access MyCtrlScope though, see <b>{{obj.prop}}</b></h1> how can I access the <b>SOME_CONST</b> value in my parent\'s link function? is this even a good idea? {{SOME_CONST}}. I really don\'t want to put everything inside the MyCtrl',
}
});
See this update: http://jsfiddle.net/uN2uv/
I just had the same problem and finally solved it with the angular manual ;)
In short: you need to use a controller in your parent directive and require that controller in your child directive. This way you are able to get your parent properties.
See https://docs.angularjs.org/guide/directive Chapter: Creating Directives that Communicate
I changed your fiddle to use a controller, now you can access your constant: https://jsfiddle.net/bbrqdmt3/1/
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.obj = {prop:'foo'};
}
myApp.directive('parent', function() {
return {
scope: true,
transclude: true,
restrict: 'EA',
template: '<div ng-transclude><h1>I\'m parent {{obj.prop}}<h1></div>',
controller: function($scope) {
this.getConst= function() {
return 'someConst';
}
},
}
});
myApp.directive('child', function() {
return {
restrict: 'EA',
require : '^parent',
link: function(scope, element, attrs, ctrl) {
scope.value= ctrl.getConst();
},
template: '<h1>I\'m child.... I want to access my parent\'s stuff, but I can\'t. I can access MyCtrlScope though, see <b>{{obj.prop}}</b></h1> how can I access the <b>SOME_CONST</b> value in my parent\'s link function? is this even a good idea? {{value}}. I really don\'t want to put everything inside the MyCtrl',
}
});
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