我正在尝试从transcluding child指令的link函数访问父指令的控制器方法,但是没有运气。当我将子项作为父模板的一部分包含在内或从父ng控制器传递它时,它可以工作。不应该转换在角度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>
答案 0 :(得分:0)
由于您将scope: { ctrlFn: '&', }
放在outerDirective
上,因此会创建一个isolate scope:
“隔离”作用域与常规作用域的不同之处在于,它不原型地继承自其父作用域。这在创建可重用的组件时非常有用,该组件不应意外读取或修改父范围中的数据。请注意,没有
template
或templateUrl
的isolate作用域指令不会将isolate作用域应用于其子元素。
隔离作用域的一个用例是能够从链接函数中scope.$watch
作用域上的表达式,即使您的指令没有模板,该用法也很有用。孤立范围的另一个用途是在指令模板中为指令和插值提供数据(如果有的话)。
但是,这个范围被被包容的孩子忽略了。超越时,您会得到一个特殊的transclusion scope,它会特别忽略此隔离范围:
此范围是特殊的,因为它是指令范围的子级(因此在删除指令范围时会被销毁),但它继承了从其获取范围的属性。
这意味着传递给scope
函数的link
仅对模板可见。凡是被超越的内容,都会看到您指令的父级范围,并忽略隔离范围。
伪指令彼此通信的一种方式是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: '='
,因为'&'
适用于要在调用程序中执行表达式的情况。例如,当您执行类似<my-directive on-something-happened="x = $event.value"/>
的操作时。但是,您正在尝试将函数作为值传递,而不是试图传递可执行的角度表达式。
请注意,我在scope: {}
上设置了innerDirective
,但我将其保留为空。这向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交互的操作,而不是用来间接连接根应用程序控制器的任何操作。