Angularjs 指令中的访问控制器作用域
我创建了一个简单的指令,用于显示我正在创建的Angularjs 指令中的访问控制器作用域,angularjs,isolate-scope,Angularjs,Isolate Scope,我创建了一个简单的指令,用于显示我正在创建的的排序列标题 ngGrid.directive("sortColumn", function() { return { restrict: "E", replace: true, transclude: true, scope: { sortby: "@", onsort: "=" }, templat
的排序列标题
ngGrid.directive("sortColumn", function() {
return {
restrict: "E",
replace: true,
transclude: true,
scope: {
sortby: "@",
onsort: "="
},
template: "<span><a href='#' ng-click='sort()' ng-transclude></a></span>",
link: function(scope, element, attrs) {
scope.sort = function () {
// I want to call CONTROLLER.onSort here, but how do I access the controller scope?...
scope.controllerOnSort(scope.sortby);
};
}
};
});
ngGrid.directive(“sortColumn”,function()){
返回{
限制:“E”,
替换:正确,
是的,
范围:{
肮脏的:“@”,
onsort:“=”
},
模板:“”,
链接:函数(范围、元素、属性){
scope.sort=函数(){
//我想在这里调用CONTROLLER.onSort,但如何访问控制器作用域?。。。
scope.controllerOnSort(scope.sortby);
};
}
};
});
下面是一些正在创建的表标题的示例:
<table id="mainGrid" ng-controller="GridCtrl>
<thead>
<tr>
<th><sort-column sortby="Name">Name</sort-column></th>
<th><sort-column sortby="DateCreated">Date Created</sort-column></th>
<th>Hi</th>
</tr>
</thead>
指令中的
要求使用ngController
并将链接功能修改为:
ngGrid.directive("sortColumn", function() {
return {
...
require: "ngController",
...
link: function(scope, element, attrs, ngCtrl) {
...
}
};
});
你得到的是你的控制器,GridCtrl
。但你不了解它的范围;您必须按照以下方式进行操作:
xxxx.controller("GridCtrl", function($scope, ...) {
// add stuff to scope as usual
$scope.xxxx = yyyy;
// Define controller public API
// NOTE: USING this NOT $scope
this.controllerOnSort = function(...) { ... };
});
从link函数调用它,简单如下:
ngCtrl.controllerOnSort(...);
请注意,这需要获得第一个父级ngController
。如果在GridCtrl
和指令之间指定了另一个控制器,您将得到该控制器
演示原理的小提琴(使用方法访问父控制器的指令):
人们担心这种解决方案可能会引入不必要的紧耦合。如果这确实是一个问题,可以通过以下方式解决:
创建一个与控制器并排的指令,让我们称之为master
:
<table id="mainGrid" ng-controller="GridCtrl" master="controllerOnSort()">
使用$parse
服务,可以从主控制器的成员方法调用指定的方法。请参阅更新的fiddle实现此原则:创建第二个指令作为包装器:
ngGrid.directive("columnwrapper", function() {
return {
restrict: "E",
scope: {
onsort: '='
}
};
});
然后,您只需在outer指令中引用要调用的函数一次:
<sort-column onSort="controllerOnSort" sortby="Name">Name</sort-column>
require: "^master"
<columnwrapper onsort="controllerOnSort">
<sort-column sortby="Name">Name</sort-column>
<sort-column sortby="DateCreated">Date Created</sort-column>
</columnwrapper>
请参阅此小提琴以了解工作示例:
当然,如果您不关心硬编码的依赖项,那么您也可以只使用一个指令,通过
我还有一把小提琴,上面写着:
此解决方案将与另一个答案()中的解决方案具有相同的效果(在硬耦合方面具有相同的批评),但至少比该解决方案简单一些。不管怎样,如果你努力结合,我不认为引用控制器有什么意义,因为它很可能一直在$scope.$parent中可用(但要注意设置作用域的其他元素)
不过,我会选择第一种解决方案。它添加了一些小标记,但解决了问题并保持了清晰的分离。另外,如果将第二个指令用作直接包装器,则可以确保$scope.$parent与外部指令匹配。还有另一种方法可以做到这一点,尽管鉴于我相对缺乏经验,我无法说明这种解决方案是否适合。我无论如何都会把它传下去,仅供参考
在列中,创建范围变量属性:
<sort-column data-sortby="sortby">Date Created</sort-column>
然后在控制器中添加排序功能:
$scope.onSort = function(val) {
$scope.sortby = val;
}
$scope.$on("_sortFinished", function(event, message){
..do something...
});
然后在标记框中单击:
<sort-column data-sortby="sortby" ng-click="onSort('DateCreated')">Date Created</sort-column>
在“link:”函数中添加$watch:
scope.$watch('sortby', function () {
... your sort logic here ...
}
这种方法的美妙之处在于,指令完全解耦,您不需要从指令中调用onSort,因为在执行路径的这一部分期间,您实际上没有将onSort留在控制器中
如果需要告诉控制器等待排序完成,可以在控制器中定义事件:
$scope.onSort = function(val) {
$scope.sortby = val;
}
$scope.$on("_sortFinished", function(event, message){
..do something...
});
然后,在指令中,只需发出事件,即可完成该过程:
$scope.$emit('_sortFinished');
还有其他方法可以做到这一点,这种方式增加了一些紧密耦合,因为你的控制器必须监听。您的指令必须发出特定的甚至。。。但这对你来说可能不是问题,因为他们无论如何都是密切相关的
&local scope属性允许指令的使用者传入指令可以调用的函数
见详情
下面是一个示例,它显示了如何从指令代码在回调函数中传递参数。称我为疯子,但似乎更容易通过内置方法从元素中获取控制器,而不是摆弄require
:
var mod = angular.module('something', []).directive('myDir',
function () {
return {
link: function (scope, element) {
console.log(element.controller('myDir'));
},
controller: function () {
this.works = function () {};
},
scope: {}
}
}
);
我不确定以这种方式将指令和控制器紧密耦合是最好的主意。它肯定会起作用,但无论何时使用此指令,都需要在控制器上定义一个非常特定的方法。他目前的做法可以说是更好的实践。事实上,这些组件已经耦合在一起了,因为一个组件需要另一个组件才能正确运行。该指令取决于是否存在具有特定方法的控制器(任何控制器),此处为controllerOnSort()
。这相当于让控制器在强类型langs中实现接口。父控制器可以通过require:“^ngController”
规范设置为可选。不正确,因为如果您查看他的问题,他是通过属性传入回调。该名称将指令与任何控制器或作用域解耦。在他的示例中,排序方法可以命名为任何名称,而您的排序方法需要严格的命名。他的示例还允许从层次结构中的任何范围传入方法,而您的示例则查找直接父级。他的抱怨仅仅是他必须在所有专栏中重复这个属性。事实上,这是一个折衷的方法:你获得了便利,你失去了耦合(理论上,因为这些东西已经在逻辑上耦合了),感谢你的彻底回应。“紧密耦合”是一个有效的观点,尽管对于这种用法我并不介意,因为我只希望该指令与网格控件一起使用,所以我认为在这种情况下紧密耦合没有什么大问题
$scope.$emit('_sortFinished');
var mod = angular.module('something', []).directive('myDir',
function () {
return {
link: function (scope, element) {
console.log(element.controller('myDir'));
},
controller: function () {
this.works = function () {};
},
scope: {}
}
}
);