我可以在指令中要求使用 ng-controller 设置控制器吗?
Can I require a controller, in a directive, set with ng-controller?
我有(某种程度上)以下 html:
<div ng-controller="MyController">
<my-sub-directive></my-sub-directive>
</div>
控制器的外观并不重要:
app.controller("MyController", function($scope) {
$scope.foo = "bar";
})
我的指令是这样的:
function mySubDirective() {
return {
restrict: "E",
templateUrl:"aTemplate.html",
require: "^MyController",
link: function($scope, element) {
}
};
}
app.directive("mySubDirective", mySubDirective);
在文档中,他们总是在 require
-属性 中指定另一个指令,但它说这意味着您需要控制器。所以我想尝试这个解决方案。但是我收到错误
"Controller 'MyController', required by directive 'mySubDirective', can't be found".
如果由 ng-controller 设置,是否无法从指令中要求控制器?
你只能做:
require: "^ngController"
所以,你不能比这更具体,即你不能按名称要求 "MainCtrl"
或 "MyController"
,但它会给你控制器实例:
.controller("SomeController", function(){
this.doSomething = function(){
//
};
})
.directive("foo", function(){
return {
require: "?^ngController",
link: function(scope, element, attrs, ctrl){
if (ctrl && ctrl.doSomething){
ctrl.doSomething();
}
}
}
});
<div ng-controller="SomeController">
<foo></foo>
</div>
不过,我认为这不是一个好方法,因为它使指令非常依赖于使用它的地方。您可以按照\评论中的建议直接传递控制器实例 - 它使它更加明确:
<div ng-controller="SomeController as ctrl">
<foo ctrl="ctrl"></foo>
</div>
但它仍然是一个过于通用的对象,很容易被您的指令的用户滥用。
相反,公开定义良好的 API(通过属性)并将引用传递给控制器中定义的 functions/properties:
<div ng-controller="SomeController as ctrl">
<foo do="ctrl.doSomething()"></foo>
</div>
您可以在指令 link 函数中使用 element.controller()
来测试由 ngController
指定的最近的控制器。此方法的一个限制是它不会告诉您它是哪个控制器。您可能有几种方法可以做到这一点,但我选择命名控制器构造函数,并将其公开在范围内,因此您可以使用 instanceof
// Deliberately not adding to global scope
(function() {
var app = angular.module('my-app', []);
// Exposed in so can do "instanceof" in directive
function MyController($scope) {}
app.controller('MyController', MyController);
app.directive("foo", function(){
return {
link: function($scope, $element){
var controller = $element.controller();
// True or false depending on whether the closest
// ngController is a MyController
console.log(controller instanceof MyController);
}
};
})
})();
您可以在 http://plnkr.co/edit/AVmr7Eb7dQD70Mpmhpjm?p=preview
看到这个
但是,如果您嵌套了 ngController
,并且您想要测试不一定最接近的那一个,这将不起作用。为此,您可以定义一个递归函数来遍历 DOM 树:
app.directive("foo", function(){
function getAncestorController(element, controllerConstructor) {
var controller = element.controller();
if (controller instanceof controllerConstructor) {
return controller;
} else if (element.parent().length) {
return getAncestorController(element.parent(), controllerConstructor);
} else {
return void(0); // undefined
}
}
return {
link: function(scope, element){
var controller = getAncestorController(element, MyController);
// The ancestor controller instance, or undefined
console.log(controller);
}
};
})
您可以在 http://plnkr.co/edit/xM5or4skle62Y9UPKfwG?p=preview
看到这个
作为参考,docs 指出 controller
函数可用于查找由 ngController
指定的控制器:
By default retrieves controller associated with the ngController directive
我有(某种程度上)以下 html:
<div ng-controller="MyController">
<my-sub-directive></my-sub-directive>
</div>
控制器的外观并不重要:
app.controller("MyController", function($scope) {
$scope.foo = "bar";
})
我的指令是这样的:
function mySubDirective() {
return {
restrict: "E",
templateUrl:"aTemplate.html",
require: "^MyController",
link: function($scope, element) {
}
};
}
app.directive("mySubDirective", mySubDirective);
在文档中,他们总是在 require
-属性 中指定另一个指令,但它说这意味着您需要控制器。所以我想尝试这个解决方案。但是我收到错误
"Controller 'MyController', required by directive 'mySubDirective', can't be found".
如果由 ng-controller 设置,是否无法从指令中要求控制器?
你只能做:
require: "^ngController"
所以,你不能比这更具体,即你不能按名称要求 "MainCtrl"
或 "MyController"
,但它会给你控制器实例:
.controller("SomeController", function(){
this.doSomething = function(){
//
};
})
.directive("foo", function(){
return {
require: "?^ngController",
link: function(scope, element, attrs, ctrl){
if (ctrl && ctrl.doSomething){
ctrl.doSomething();
}
}
}
});
<div ng-controller="SomeController">
<foo></foo>
</div>
不过,我认为这不是一个好方法,因为它使指令非常依赖于使用它的地方。您可以按照\评论中的建议直接传递控制器实例 - 它使它更加明确:
<div ng-controller="SomeController as ctrl">
<foo ctrl="ctrl"></foo>
</div>
但它仍然是一个过于通用的对象,很容易被您的指令的用户滥用。
相反,公开定义良好的 API(通过属性)并将引用传递给控制器中定义的 functions/properties:
<div ng-controller="SomeController as ctrl">
<foo do="ctrl.doSomething()"></foo>
</div>
您可以在指令 link 函数中使用 element.controller()
来测试由 ngController
指定的最近的控制器。此方法的一个限制是它不会告诉您它是哪个控制器。您可能有几种方法可以做到这一点,但我选择命名控制器构造函数,并将其公开在范围内,因此您可以使用 instanceof
// Deliberately not adding to global scope
(function() {
var app = angular.module('my-app', []);
// Exposed in so can do "instanceof" in directive
function MyController($scope) {}
app.controller('MyController', MyController);
app.directive("foo", function(){
return {
link: function($scope, $element){
var controller = $element.controller();
// True or false depending on whether the closest
// ngController is a MyController
console.log(controller instanceof MyController);
}
};
})
})();
您可以在 http://plnkr.co/edit/AVmr7Eb7dQD70Mpmhpjm?p=preview
看到这个但是,如果您嵌套了 ngController
,并且您想要测试不一定最接近的那一个,这将不起作用。为此,您可以定义一个递归函数来遍历 DOM 树:
app.directive("foo", function(){
function getAncestorController(element, controllerConstructor) {
var controller = element.controller();
if (controller instanceof controllerConstructor) {
return controller;
} else if (element.parent().length) {
return getAncestorController(element.parent(), controllerConstructor);
} else {
return void(0); // undefined
}
}
return {
link: function(scope, element){
var controller = getAncestorController(element, MyController);
// The ancestor controller instance, or undefined
console.log(controller);
}
};
})
您可以在 http://plnkr.co/edit/xM5or4skle62Y9UPKfwG?p=preview
看到这个作为参考,docs 指出 controller
函数可用于查找由 ngController
指定的控制器:
By default retrieves controller associated with the ngController directive