Контроллеры директив AngularJS, требующие родительских директивных контроллеров?

Я мог бы подумать об этом полностью назад, но я пытаюсь сделать три вложенных директивы, позвонил им: экран, компонент и виджет. Я хочу, чтобы виджет мог запускать некоторое поведение в компоненте, что, в свою очередь, вызывает некоторое поведение на экране. Итак:

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

Я могу потребовать родительские компоненты в ссылке fn виджета с помощью require: "^component", но как я могу предоставить контроллеру компонентов доступ к его экрану?

Что мне нужно - это WHAT в компоненте, поэтому, когда вы нажимаете кнопку виджета, он предупреждает "скрипучий!".

Спасибо.

Ответ 1

Вот два способа решения вашей проблемы:

  • Поскольку вы используете scope: true, все области, на которые наследуется прототип. Поэтому, если вы определяете свои методы на $scope вместо this в контроллере screen, то оба component и widget будут иметь доступ к функции doSomethingScreeny.
    Fiddle.
  • Определите функцию связи на component и require: '^screen'. В функции связи сохраните свойство screenCtrl в свойстве scope, затем вы можете получить доступ к нему в контроллере директивы (введите $scope).
    Fiddle.

Ответ 2

Большая часть этих материалов выходит из строя, когда вы хотите напрямую обращаться к свойствам или методам из родительского контроллера при создании контроллера. Я нашел другое решение, используя инъекцию зависимостей и используя службу $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) {});

Этот метод лучше тестируется и не загрязняет вашу область с помощью нежелательных контроллеров.

Ответ 3

return {scope: true} или return {scope: false} не влияет на переменную $scope в контроллере: function ($ scope) {} в каждой директиве, но тег директивы должен быть помещен в ng-контроллер или ng -app.

JSFiddle

JSFiddle

Ответ 4

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>