Reputation: 14563
I might be thinking about this completely backwards, but I'm trying to make three nested directives, lets call them: screen, component and widget. I want widget to be able to trigger some behavior in component, which in turn triggers some behavior in screen. So:
.directive('screen', function() {
return {
scope: true,
controller: function() {
this.doSomethingScreeny = function() {
alert("screeny!");
}
}
}
})
.directive('component', function() {
return {
scope: true,
controller: function() {
this.componentFunction = function() {
WHAT.doSomethingScreeny();
}
}
}
})
.directive('widget', function() {
return {
scope: true,
require: "^component",
link: function(scope, element, attrs, componentCtrl) {
scope.widgetIt = function() {
componentCtrl.componentFunction();
};
}
}
})
<div screen>
<div component>
<div widget>
<button ng-click="widgetIt()">Woo Hoo</button>
</div>
</div>
</div>
I can require parent components in a widget's link fn using require: "^component"
, but how do I further give components controller access to its containing screen?
What I need is the WHAT in component so when you click the widget's button it alerts "screeny!".
Thanks.
Upvotes: 30
Views: 36937
Reputation: 4595
var myApp = angular.module('myApp', [])
.directive('screen', function() {
return {
scope: true,
controller: function() {
this.doSomethingScreeny = function() {
alert("screeny!");
}
}
}
})
.directive('component', function() {
return {
scope: true,
controller: function($element) {
this.componentFunction = function() {
$element.controller('screen').doSomethingScreeny();
}
}
}
})
.directive('widget', function() {
return {
scope: true,
controller: function($scope, $element) {
$scope.widgetFunction = function() {
$element.controller('component').componentFunction();
}
}
}
})
.controller('MyCtrl', function($scope) {
$scope.name = 'Superhero';
})
<body ng-app="myApp">
<div ng-controller="MyCtrl">
<div screen>
<div component>
<div widget>
<button ng-click="widgetFunction()">Woo Hoo</button>
</div>
</div>
</div>
</div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.min.js"></script>
If you want to access a function defined in screen directive controller from component directive controller (not a link function), you can use $element.controller('screen').doSomethingScreeny()
(from component directive).
Angular documentation:
controller(name)
- retrieves the controller of the current element or its parent. By default retrieves controller associated with thengController
directive. Ifname
is provided as camelCase directive name, then the controller for this directive will be retrieved (e.g.'ngModel'
).
Upvotes: 0
Reputation: 87
return { scope: true } or return { scope: false } is not affect to $scope variable in controller: function($scope) {} in each directive, but directive tag have to putted into the ng-controller or ng-app tag.
Upvotes: 0
Reputation: 317
Most of this stuffs fails when you want to directly access properties or methods from the parent controller on controller creation. I found another solution by using dependency injection and using the $controller
service.
.directive('screen', function ($controller) {
return {
require: '^parent',
scope: {},
link: function (scope, element, attr, controller) {
$controller('MyCtrl', {
$scope: scope,
$element: element,
$attr, attr,
controller: controller
});
}
}
})
.controller('MyCtrl, function ($scope, $element, $attr, controller) {});
This method is better testable and does not pollute your scope with unwanted controllers.
Upvotes: 5
Reputation: 364677
Here are two ways you could solve your problem:
scope: true
, all scopes prototypically inherit. So if you define your methods on $scope
instead of on this
in the screen
controller, then both component
and widget
will have access to function doSomethingScreeny
.
component
and require: '^screen'
. In the link function, save the screenCtrl to a scope property, then you can access it in the directive's controller (inject $scope
).
Upvotes: 36