AngularJS:需要来自child指令的父指令

时间:2015-09-15 13:43:51

标签: javascript angularjs

请考虑Plunk

我正在尝试为复杂的指令访问设置测试用例,但是从父指令调用方法时出错:

父指令

app.directive('topParentDirective', [
    '$compile',
    function($compile){
      return {
        restrict: 'E',
        transclude: true,
        template: '<h3>I\'m the parent directive.</h3><div ng-transclude></div>',
        controller: function($scope) {
          $scope.ActivateMe = function(callerName) {
            alert('Parent activated from caller ' + callerName);
          };
        }
      };
    }
]);

儿童指令

app.directive('interactingChildDirective', [
    '$compile',
    function($compile){
      return {
        scope: {
          name: '@'
        },
        restrict: 'E',
        require: ['^topParentDirective'],
        templateUrl: 'interactingChildDirective.html',
        link: function($scope, $elem, $attrs, $ctrl) {
          var self = {};

          console.log($ctrl);

          $scope.CallTopParent = function() {
            $ctrl.ActivateMe($attrs.name);
          };
        }
      };
    }
]);

InteractingChildDirective.html

包含:

My name is {{name}}, <button ng-click="CallTopParent()">Click me</button>!

HTML

<body ng-app="ngApp">
<div ng-controller="myController">
  <top-parent-directive>
    <interacting-child-directive name="Child 1"></interacting-child-directive>
  </top-parent-directive>
</div>
</body>

问题

TypeError: $ctrl.ActivateMe is not a function
    at n.$scope.CallTopParent 

这是因为$ ctrl似乎不正确。

我该如何解决这个问题?这可能有点荒谬了......

3 个答案:

答案 0 :(得分:2)

应该是

    controller: function($scope) {
      this.ActivateMe = function(callerName) {
        alert('Parent activated from caller ' + callerName);
      };
    }

因为$ ctrl需要控制器的this

答案 1 :(得分:1)

因为您已将子项嵌套在父控制器中,所以您可以使用

访问它的范围
$scope.$parent

在你的情况下:

$scope.$parent.ActivateMe($attrs.name);

Plunker:http://plnkr.co/edit/YyppT9pWnn1PFWJXBAOF?p=info

答案 2 :(得分:0)

estus的回答与评论相结合,有效。为了完整,我想要的场景的工作样本:

Plunkr sample

更新了Html

<body ng-app="ngApp">
    <div ng-controller="myController">
      <top-parent-directive>

        <interacting-child-directive name="Child 1">

          <meaningless-level-directive header="Sub 1">
            <interacting-child-directive name="Child 3"/>
          </meaningless-level-directive>

        </interacting-child-directive>

        <interacting-child-directive name="Child 2">

          <meaningless-level-directive header="Sub 2">
            <interacting-child-directive name="Child 4"/>
          </meaningless-level-directive>

        </interacting-child-directive>

      </top-parent-directive>
    </div>
</body>

meaninglessLevelDirective

顾名思义,这只是为了增加额外的水平:

app.directive('meaninglessLevelDirective', [
  '$compile',
  function($compile){
    return {
      scope: {
        header: '@'
      },
      restrict: 'E',
      transclude: true,
      templateUrl: 'meaninglessLevelDirective.html',
      controller: function($scope){
      }
    };
  }
]);

meaninglessLevelDirective.html

<div class="meaninglessLevelStyle">
  {{header}}
  <div style="padding: 10px" ng-transclude>
  </div>  
</div>