告诉子指令在父指令完成DOM操作之后执行操作
Tell child directive to act after a parent directive has done DOM actions?
假设我们有一些嵌套指令:
<big-poppa>
<baby-bird></baby-bird>
</big-poppa>
假设big-poppa
想要创建一个所有子指令都可以共享的组件。把它放在控制器中会很好,但这个组件需要DOM,所以它需要在链接函数中构建。
假设baby-bird
组件想要从组件中读取。也许它想从中听到事件,也许向它发送一两个命令。挑战在于,控制器触发dom(首先是父对象,然后是子对象(,后链接方法触发另一个方向,因此执行顺序如下:
- bigPoppa控制器
- babyBird控制器
- babyBird链接
- bigPoppa链接
父级的link
方法在子级的之后激发,这对我来说是指令内通信挑战的原因。我希望父级构建共享DOM组件,但DOM构建应该在链接函数中进行。因此,父级在任何子级之后构建组件
我可以通过超时(粗略(或承诺(复杂/非惯用?(来解决这个问题。这是小提琴:
http://jsfiddle.net/8xF3Z/4/
var app = angular.module('app',[]);
app.directive('bigPoppa', function($q){
return {
restrict: 'E',
controller: function($scope){
console.log('bigPoppa controller');
var d = $q.defer()
$scope.bigPoppaLinkDeferred = d
$scope.bigPoppaLink = d.promise
},
link: function(scope, el, attrs){
console.log('bigPoppa link');
scope.componentThatNeedsDom = { el: el, title: 'Something' };
scope.bigPoppaLinkDeferred.resolve()
}
}
});
app.directive('babyBird', function(){
return {
restrict: 'E',
controller: function(){ console.log('babyBird controller'); },
link: function(scope, el, attrs, bigPoppaController){
console.log('babyBird link');
// console.log('poppa DOM component', scope.componentThatNeedsDom); // Not yet defined, because the parent's link function runs after the child's
// setTimeout(function(){ console.log('poppa DOM component', scope.componentThatNeedsDom); }, 1); // Works, but gross
scope.bigPoppaLink.then(function(){
console.log('poppa DOM component', scope.componentThatNeedsDom);
}); // works, but so complex!
}
}
});
console.log(''); // blank line
这里有很多背景,但我的问题很简单:
在父指令运行其post-link函数后,是否有一种干净的方法可以在子指令中执行行为?
也许是使用priority
的一种方式,或者pre
和post
链接方法?
实现这一点的另一种方法是使用纯Angular范围事件从父链接函数到子链接函数进行通信。
var app = angular.module('app',[]);
app.directive('bigPoppa', function($q){
return {
restrict: 'E',
link: function(scope, el, attrs){
scope.$broadcast('bigPoppa::initialised', {el: el, title: 'Something'});
}
}
});
app.directive('babyBird', function(){
return {
restrict: 'E',
link: function(scope, el, attrs) {
scope.$on('bigPoppa::initialised', function(e, componentThatNeedsDom) {
console.log('poppa DOM component in bird linking function', componentThatNeedsDom);
});
}
}
});
这可以在http://jsfiddle.net/michalcharemza/kerptcrw/3/
这种方式有好处:
- 没有范围观察者
- 它使用了一个清晰的消息发送/接收范式,而不是依赖于控制器/链接前/链接后阶段的顺序,因此我认为它更容易理解和维护
- 不依赖于pre-link函数中的行为,这不是典型的,并且您必须注意不要在其中放入修改DOM的行为
- 不向作用域层次结构添加变量(但添加事件(
基于实验,如果我错了,我会要求更正,我发现Angular按以下顺序运行其编译阶段:
1. compile methods of all directives both parent and child, run in flat order
2. parent controller
3. parent pre-link
4. (all actions of children directives)
5. parent post-link (AKA regular `link` function)
这个实验的公共要点如下:https://gist.github.com/SimpleAsCouldBe/4197b03424bd7766cc62
有了这些知识,父指令上的pre-link
回调似乎非常适合。解决方案如下:
var app = angular.module('app',[]);
app.directive('bigPoppa', function($q){
return {
restrict: 'E',
compile: function(scope, el) {
return {
pre: function(scope, el) {
console.log('bigPoppa pre');
scope.componentThatNeedsDom = { el: el, title: 'Something' };
}
};
}
}
});
app.directive('babyBird', function(){
return {
restrict: 'E',
link: function(scope, el, attrs, bigPoppaController){
console.log('babyBird post-link');
console.log('bigPoppa DOM-dependent component', scope.componentThatNeedsDom);
}
}
});
http://jsfiddle.net/a5G72/1/
感谢@runTarm和这个问题为我指明了pre-link
的方向。
有两种模式可以用来实现您想要的
-
通过
require
调用父指令的控制器,并在其中的某个值上创建一个$watch
er,可以在子链接函数中包含对父指令控制器中的更改做出反应的代码。 -
如果您需要在父链接函数中运行一些东西,然后才更改其控制器中的值,则可以向
require
本身发出指令,并从链接函数访问控制器。
在你的例子中把这些放在一起就变成了:
var app = angular.module('app',[]);
app.directive('bigPoppa', function($q){
return {
restrict: 'E',
require: 'bigPoppa',
controller: function($scope) {
this.componentThatNeedsDom = null;
},
link: function(scope, el, attrs, controller){
controller.componentThatNeedsDom = { el: el, title: 'Something' };
}
}
});
app.directive('babyBird', function(){
return {
restrict: 'E',
require: '^bigPoppa',
link: function(scope, el, attrs, bigPoppaController){
scope.$watch(function() {
return bigPoppaController.componentThatNeedsDom
}, function(componentThatNeedsDom) {
console.log('poppa DOM component in bird linking function', componentThatNeedsDom);
});
}
}
});
可以在http://jsfiddle.net/4L5bj/1/。这比您的答案有好处,因为它不依赖于范围继承,并且不会用仅由这些指令使用的值污染范围。
- AngularJS操作父'指令中的DOM
- 我应该只在指令的链接 fn 中进行 DOM 操作吗?
- AngularJs 在指令中操作来自服务响应的数据
- 通过指令属性传达操作
- 使用 angularjs 指令操作范围值
- 表单操作无法正常工作.它不会移动到指令链接,即<表单 action=“”>
- 角度指令 DOM 操作行为
- 更新指令中的attrs值 - 如何在AngularJS中执行此操作
- 处理开机自检后从 Angular 控制器到指令的成功/错误 DOM 操作
- 如何在不使用指令的情况下操作ng-if内部的元素
- 如何在某个操作后刷新AngularJS指令
- angularjs指令来操作文本值
- 由于子指令引发的事件,正在操作父指令的DOM
- Angularjs-当dom操作被分配给按钮点击时,它是有效的,在指令中它是不完整的
- 告诉子指令在父指令完成DOM操作之后执行操作
- 一个指令用于多个DOM操作
- Angularjs指令慢dom操作
- 多个控制器在一个Angular指令中操作内容
- 监视{{values}}上的变化以触发DOM的指令操作
- 无法在指令链接中操作继承的作用域(konami代码指令实现)