Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS directive controllers requiring parent directive controllers?

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.

like image 559
nicholas Avatar asked Mar 25 '13 19:03

nicholas


People also ask

What AngularJS directive defines a controller?

AngularJS ng-controller Directive The ng-controller directive adds a controller to your application. In the controller you can write code, and make functions and variables, which will be parts of an object, available inside the current HTML element. In AngularJS this object is called a scope.

What is the difference between AngularJS directives and controllers?

A controller is usually used to contain and maintain the logic for your view, which gets bound to your view via $scope. A directive is something that you might use repeatedly and is called in your view directly through the directive name which you can pass in as an attribute.

Can we use multiple directives in AngularJS?

... is quite illustrative as AngularJS doesn't allow multiple directives (on the same DOM level) to create their own isolate scopes. According to the documentation, this restriction is imposed in order to prevent collision or unsupported configuration of the $scope objects.

What is parent and child controller AngularJS?

Angular scopes include a variable called $parent (i.e. $scope. $parent ) that refer to the parent scope of a controller. If a controller is at the root of the application, the parent would be the root scope ( $rootScope ). Child controllers can therefore modify the parent scope since they access to it.


2 Answers

Here are two ways you could solve your problem:

  1. Since you are using 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.
    Fiddle.
  2. Define a link function on 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).
    Fiddle.
like image 149
Mark Rajcok Avatar answered Oct 25 '22 02:10

Mark Rajcok


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.

like image 28
mlegenhausen Avatar answered Oct 25 '22 02:10

mlegenhausen