[英]transcluded content requires the controller of the transcluding directive
[英]Passing parent controller method to transcluding child directive
我正在尝试从包含子指令的链接功能访问父指令的控制器方法,但运气不好。 当我将孩子作为父母模板的一部分或从父母ng-controller传递给孩子时,它会起作用。 不应在角度1.4中也包括创建子范围吗?
使用Javascript:
var app = angular.module('app', []);
app.controller('AppController', function($scope) {
$scope.ctrlFn = function() {
alert('hello');
};
});
app.directive('outerDirective', function() {
return {
restrict: 'A',
scope: {
ctrlFn : '&'
},
controller: 'AppController',
transclude:true,
template: '<div ng-transclude></div>',
link: function(scope, element, attributes) {
scope.outerFunction = function() {
scope.ctrlFn();
};
}
};
});
app.directive('innerDirective', function() {
return {
scope: {
ctrlFn : '&'
},
replace:true,
template: '<button ng-click="innerFunction()">Child Directive</button>',
link: function(scope, element, attributes) {
scope.innerFunction = function() {
scope.ctrlFn();
};
}
};
});
HTML:
<div id="app" ng-app="app">
<div outer-directive ctrl-fn="ctrlFn">
<div inner-directive ctrl-fn="ctrlFn()"></div>
</div>
</div>
因为您将scope: { ctrlFn: '&', }
放在outerDirective
,所以它创建了一个隔离范围 :
“隔离”作用域与常规作用域的不同之处在于,它不原型地继承自其父作用域。 这在创建可重用的组件时非常有用,该组件不应意外读取或修改父范围中的数据。 请注意,没有
template
或templateUrl
的隔离范围指令不会将隔离范围应用于其子元素。
隔离作用域的一个用例是能够scope.$watch
链接函数中作用域上的scope.$watch
表达式,即使指令没有模板也很有用。 隔离范围的另一种用途是在指令模板中为指令和插值提供数据(如果有的话)。
但是,这个范围被被包容的孩子忽略了。 包含时,您会得到一个特殊的包含范围 ,它会特别忽略此隔离范围:
此范围是特殊的,因为它是指令范围的子级(因此,在销毁指令范围时会被销毁),但是它继承了从中获取该范围的属性。
这意味着传递给link
函数的scope
仅对模板可见。 所包含的任何内容都将看到您指令的父范围,而忽略隔离范围。
指令彼此通信的一种方法是require
。 require指令可以将容器指令的控制器注入到任何子级的link
函数中。 另外, require
通过DOM树而不是范围继承树来搜索祖先。 因此,当您需要控制器时,被包含的内容可以获取包含该内容的指令的控制器。 例如,您的代码可以通过以下方式适应使用控制器:
JavaScript的:
var app = angular.module('app', []);
app.controller('AppController', function($scope) {
$scope.ctrlFn = function() {
alert('hello');
};
});
app.directive('outerDirective', function() {
return {
restrict: 'A',
scope: {
ctrlFn : '='
},
controller: function OuterDirectiveController($scope) {
this.outerFunction = function () {
return $scope.ctrlFn();
};
},
transclude:true,
template: '<div ng-transclude></div>'
};
});
app.directive('innerDirective', function() {
return {
replace:true,
template: '<button ng-click="innerFunction()">Child Directive</button>',
link: function(scope, element, attributes, outerDirective) {
scope.innerFunction = function() {
outerDirective.outerFunction();
};
},
scope: {},
require: '^outerDirective'
};
});
注意,我还将ctrlFn: '&'
更改为ctrlFn: '='
因为当您想在调用程序中执行表达式时, '&'
才是ctrlFn: '='
的。 例如,当您执行类似<my-directive on-something-happened="x = $event.value"/>
。 但是,您试图将函数作为值传递,而不是试图传递可执行的角度表达式。
注意,我在innerDirective
上设置了scope: {}
,但我将其保留为空。 这向AngularJS指示了我想要一个隔离范围-我不想覆盖父范围中的任何值。 然后在链接函数中,填充scope.innerFunction
以便我的模板可以访问引用所需控制器的innerFunction
。 我也可以将控制器也直接存储在示波器上,并为innerDirective
保存几个LOC:
{
template: '<button ng-click="outerDirective.outerFunction()">Child Directive</button',
link: function (scope, element, attributes, outerDirective) {
scope.outerDirective = outerDirective;
},
// (other keys omitted for brevity).
}
HTML:
<div id="app" ng-app="app" ng-controller="AppController">
<div outer-directive ctrl-fn="ctrlFn">
<div inner-directive></div>
</div>
</div>
另请注意,我更换了您的控制器。 现在,您的AppController
使用ng-controller="AppController"
连接到根应用程序元素。 这使您可以从应用程序控制器设置范围。 然后,每个伪指令都基于传递给它们的数据独立运行,而不是用作根范围。 我认为,指令的通常用例是可重用模板或做任何需要直接与DOM交互的事情,而不是一次用于间接连接根应用程序控制器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.