2014-01-20 45 views
15

正常使用情况下角Angularjs:注入所需的指令控制器到控制器,而不是链接功能

如果你有父母的指令,并创建子指令,在父指令的控制器的方法和在你的子指令中需要父控制器。 Angular会将父控制器传递给你的子指令链接函数。

我的使用情况

我有一个使用情况下孩子的指令是另一指令父。我在中间的指令要求的顶部有指令。中间指令是底部最后一个指令所要求的。

在一个简单的世界中,我可以为中间指令创建一个链接方法和一个控制器。链接方法处理所有与顶部控制器和中间控制器传递到底部指令。

在我的情况下,中间指令的控制器中的方法必须调用父项中的方法,所以我需要中间控制器中的顶层控制器,而不是中间指令的链接函数!

问题

我怎么能注入所需的控制器到控制器,而不是链接功能

angular.module('app').directive('top', function() { 
    return { 
     $scope: true, 
     templateUrl: "top.html", 
     controller: function() { 
      this.topMethod = function() { 
       // do something on top 
      } 
     } 
    } 
}); 

angular.module('app').directive('middle', function() { 
    return { 
     $scope: true, 
     templateUrl: "middle.html", 
     require: "^top", 
     controller: function($scope, $attrs, topController) { 
      this.middleMethod = function() { 
       // do something in the middle 

       // call something in top controller, this is the part that makes everything so complicated 
       topController.topMethod(); 
      } 
     } 
    } 
}); 

angular.module('app').directive('bottom', function() { 
    return { 
     $scope: true, 
     templateUrl: "bottom.html", 
     require: "^middle", 
     link: function(scope, element, attrs, middleController) { 
      $scope.bottomMethod = function() { 
       // do something at the bottom 

       // call something in the parent controller 
       middleController.middleMethod(); 
      } 
     } 
    } 
}); 

回答

13

实际上还有另一种方式,是更简洁和is used by the angular ngModel itself

var parentForm = $element.inheritedData('$formController') || .... 

基本上它们使用控制器被存储到指令DOM元素的数据属性的事实。

仍然有点有线,但较少详细和更容易理解。

我不明白为什么你不能将所需的控制器传递给指令控制器的注入局部。

+0

我想你可能已经链接到了错误的jsFiddle。这只是一个你好世界的例子。 – rob

+6

看来,还有更简单的方法如何实现这一点: var parentForm = $ element.controller('form') – romario333

+1

我已经为此和romario333的解决方案添加了一个演示:http://work.karlhorky。 com/frontend-tricks/angular-1-inject-required-directive-controller-into-directive-controller/ –

11

的问题是在编译什么顺序指令和链接。假设我们有一个HTML的结构是这样的:

<div top> 
    <div middle> 
     <div bottom></div> 
    </div> 
</div> 

和coresponding(simplyfied)有很多调试输出的指令:

.directive('top', function() { 
    return { 
     controller : function($scope, $element, $attrs) { 
      this.topMethod = function() { 
       console.log('top method'); 
      } 
     }, 
     compile : function($element, $attrs) { 
      console.log('top compile'); 
      return { 
       pre : function($scope, $element, $attrs) { 
        console.log('top pre'); 
       }, 
       post : function($scope, $element, $attrs) { 
        console.log('top post'); 
       } 
      }; 
     } 
    } 
}) 

.directive('middle', function() { 
    return { 
     require : "^top", 
     controller : function($scope, $element, $attrs) { 
      this.middleMethod = function() { 
       console.log('middle method'); 
       $scope.topController.topMethod(); 
      } 
     }, 
     compile : function($element, $attrs) { 
      console.log('middle compile'); 
      return { 
       pre : function($scope, $element, $attrs, topController) { 
        console.log('middle pre'); 
        $scope.topController = topController; 
       }, 
       post : function($scope, $element, $attrs, topController) { 
        console.log('middle post'); 
       } 
      }; 
     }, 
    } 
}) 

.directive('bottom', function() { 
    return { 
     require : "^middle", 
     compile : function($element, $attrs) { 
      console.log('bottom compile'); 
      return { 
       pre : function($scope, $element, $attrs, middleController) { 
        console.log('bottom pre'); 
        middleController.middleMethod(); 
       }, 
       post : function($scope, $element, $attrs, middleController) { 
        console.log('bottom post'); 
       } 
      }; 
     } 
    } 
}) 

我们得到了以下的输出:

top compile 
middle compile 
bottom compile 

top pre 
middle pre 
bottom pre 

middle method 
top method 

bottom post 
middle post 
top post 

正如我们先看到的那样,调用编译函数。然后调用预链接功能,然后调用后链接功能。编译和预编译将从上到下和后编从下到上。所以我们必须在预链接功能中设置控制器。

+0

我有同样的想法,但首先执行控制器,所以topController在第一时间为空。在topcontroller必须知道所有middleController的情况下,所以他们必须调用例如topController.addChild(this)我得到一个NullpointerException。我也不知道哪些其他副作用可能出现 – maklemenz

+0

@mklemenz你说“控制器先执行”是什么意思? – michael

+0

首先控制器被执行,并且可能试图使用这个时候未定义的topController。然后,链接方法将被执行,并将topController设置为范围,如果我不在控制器中首先得到一个异常。 – maklemenz

7

从romario333的评论摘自: 的干净的解决方案是简单地使用

var topController = $element.controller('top') // pass directive name or controller name 

From the docs

控制器(名称) - 获取当前元素或其母公司的控制器。默认情况下,检索与ngController指令相关的控制器。如果名称是作为camelCase指令名称提供的,那么将检索该指令的控制器(例如'ngModel')。

$ element可以注入到您的指令控制器中。

相关问题