AngularJS指令控制器需要父指令控制器?

时间:2013-03-25 19:13:46

标签: angularjs angularjs-directive angularjs-scope

我可能会完全倒退,但我正在尝试制作三个嵌套指令,让我们调用它们:屏幕,组件和小部件。我希望widget能够触发组件中的某些行为,从而触发屏幕中的某些行为。所以:

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

我可以使用require: "^component"在小部件的链接fn中要求父组件,但是如何进一步让组件控制器访问其包含的屏幕?

我需要的是组件中的内容,因此当您单击小部件的按钮时,它会提醒“屏幕!”。

感谢。

4 个答案:

答案 0 :(得分:36)

以下两种方法可以解决您的问题:

  1. 由于您使用的是scope: true,因此所有范围都是原型继承的。因此,如果您在$scope而不是this控制器中的screen上定义方法,那么componentwidget都可以访问函数{{1 }}。
    Fiddle
  2. doSomethingScreenycomponent上定义链接功能。在link函数中,将screenCtrl保存到scope属性,然后可以在指令的控制器中访问它(注入require: '^screen')。
    Fiddle

答案 1 :(得分:5)

当你想在控制器创建时直接从父控制器访问属性或方法时,大多数这些东西都会失败。我通过使用依赖注入和使用$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) {});

此方法更易于测试,并且不会使用不需要的控制器污染您的范围。

答案 2 :(得分:0)

return {scope:true}或return {scope:false}对每个指令中的控制器:function($ scope){}中的$ scope变量没有影响,但是指令标签必须放入ng-controller或ng -app tag。

JSFiddle

JSFiddle

答案 3 :(得分:0)

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>

如果要从组件指令控制器(而不是链接功能)访问 screen 指令控制器中定义的功能,可以使用$element.controller('screen').doSomethingScreeny()(来自组件指令)。

JSFiddle

Angular documentation

  
      
  • controller(name) - 检索当前元素的控制器或   它的父母。默认情况下,检索与之关联的控制器   ngController指令。如果name作为camelCase指令提供   name,然后将检索该指令的控制器(例如   'ngModel')。
  •