web-dev-qa-db-fra.com

Contrôleurs de directive AngularJS nécessitant des contrôleurs de directive parents?

J'y réfléchis peut-être complètement à l'envers, mais j'essaie de créer trois directives imbriquées, appelons-les: écran, composant et widget. Je veux que le widget puisse déclencher un comportement dans le composant, ce qui déclenche un comportement à l'écran. Alors:

.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>

Je peux exiger des composants parents dans le lien fn d'un widget à l'aide de require: "^component", mais comment puis-je donner aux composants un accès supplémentaire au contrôleur qui le contient? 

Ce dont j'ai besoin, c'est du composant WHAT, donc lorsque vous cliquez sur le bouton du widget, celui-ci alerte "screeny!".

Merci.

30
nicholas

Voici deux manières de résoudre votre problème:

  1. Puisque vous utilisez scope: true, toutes les étendues héritent de manière prototypique. Donc, si vous définissez vos méthodes sur $scope au lieu de this dans le contrôleur screen, alors component et widget auront accès à la fonction doSomethingScreeny.
    Fiddle .
  2. Définissez une fonction de lien sur component et require: '^screen'. Dans la fonction de liaison, enregistrez la propriété screenCtrl dans une propriété de portée, puis accédez-y dans le contrôleur de la directive (inject $scope) .
    Fiddle .
35
Mark Rajcok

La plupart de ces commandes échouent lorsque vous souhaitez accéder directement aux propriétés ou aux méthodes à partir du contrôleur parent lors de la création du contrôleur. J'ai trouvé une autre solution en utilisant l'injection de dépendance et le service $controller.

.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) {});

Cette méthode est mieux testable et ne pollue pas votre portée avec des contrôleurs indésirables.

5
malte

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>

Si vous souhaitez accéder à une fonction définie dans le contrôleur de directive screen à partir du contrôleur de directive composant (pas une fonction de liaison), vous pouvez utiliser $element.controller('screen').doSomethingScreeny() (à partir de la directive composant).

JSFiddle

Angular documentation :

  • controller(name) - récupère le contrôleur de l'élément en cours ou son parent. Récupère par défaut le contrôleur associé au fichier directive ngController. Si name est fourni comme directive camelCase nom, alors le contrôleur pour cette directive sera récupéré (par exemple . 'ngModel').
0
Felix

return {scope: true} ou return {scope: false} n'est pas affecté à la variable $ scope dans le contrôleur: function ($ scope) {} dans chaque directive, mais la balise de directive doit être placée dans la balise ng-controller ou ng-app .

JSFiddle

JSFiddle

0
Lighthouse Nguyen