1

假设我们有一些嵌套指令:

<big-poppa>
  <baby-bird></baby-bird>
</big-poppa>

假设他big-poppa想要创建一个所有子指令都可以共享的组件。放在控制器里就好了,但是这个组件需要DOM,所以需要在链接函数中构建。

然后假设baby-bird组件要从组件中读取。也许它想监听它的事件,也许向它发送一两个命令。挑战在于控制器触发 dom(第一个父项,然后是子项),而 post-link 方法触发另一个方向,因此执行顺序如下所示:

  1. bigPoppa 控制器
  2. babyBird 控制器
  3. babyBird 链接
  4. 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

这里有很多背景,但我的问题很简单:

在父指令运行其链接后功能后,是否有一种干净的方法可以在子指令中执行行为?

也许是一种使用方式priority,或者preandpost链接方法?

4

3 回答 3

1

实现这一点的另一种方法是使用普通的 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 的行为。
  • 不向作用域层次结构添加变量(但它确实添加事件)
于 2014-08-07T07:29:20.767 回答
0

您可以使用 2 种模式来实现您想要的

  • 您可以在子链接函数中包含代码,该函数对父指令的控制器中的更改做出反应,方法是requireing 父指令的控制器,并$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/看到。这比您的答案有好处,它不依赖于范围继承,并且不会用仅由这些指令使用的值污染范围。

于 2014-08-06T07:26:59.173 回答
0

根据实验,如果我错了,请更正,我发现 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方向。

于 2014-08-05T17:58:27.110 回答