指令在其子女之前初始化

时间:2015-06-01 23:35:09

标签: javascript angularjs

我有2个指令,一个负责主元素<swapview>,另一个负责其子元素<view>。 但是,在加载子模板时,var views = $('view', elem);已经执行,并在DOM中找到0 <view>个元素。

我对这个问题缺乏经验,任何想法都会非常有用

  1. 如何解决异步问题?
  2. 我不确定这种可靠指令的模式是否正确。我将不胜感激任何提示,或者我可以检查的良好实践资源。
  3. HTML:

    <swapview>
      <view ng-repeat="view in views" templateurl="{{::view.template}}"></view>
    </swapview>
    

    JS

      App.directive('view', function () {
        return {
          scope:{
            templateurl: '@'
          },
          controller: function($scope) {
            $scope.getTemplateUrl = function () {
              return $scope.templateurl;
            };
          },
          template: '<ng-include src="getTemplateUrl()"/>' 
        };
      });
    
    
      App.directive('swapview', ['$swipe',function ($swipe) {
        //....        
    
        return {
          link: function (scope, elem, attrs) {
    
            var views = $('view', elem);
            var count = views.length;
    
            //......    
          },
          require: 'view'
        };
      }]);
    
    
      var ctrls = ang.module('controllers',[]);
    
      ctrls.controller('myController', ['$scope', function ($scope) {
        $scope.views = [
          {template:'templates/viewI.html'},
          {template:'templates/viewII.html'},
          {template:'templates/viewIII.html'},
          {template:'templates/viewIV.html'}
        ];
      }]);
    

    感谢您的帮助

1 个答案:

答案 0 :(得分:3)

依赖于link阶段期间存在的子DOM元素是一种非常脆弱的方法。

当元素已存在时,它会起作用:

<swapview>
  <view templateUrl="view1.html"></view>
  <view templateUrl="view2.html"></view>
</swapview>
如果您有ng-ifng-repeat 将无法正常工作,因为这两个指令会自行转换并仅评估是否自我渲染&#34;稍后&# 34;,所以在link中你会看到一个占位符注释(即使`ng-if =&#34; true&#34;)代替:

<swapview>
  <view ng-if="true" templateUrl="view1.html">
</swapview>

可以以(hackish)$timeout方法克服这个问题 - 它不会导致竞争条件 - 不是什么是黑客 - 并且实际上每次都会工作(即使有0个延迟),因为$timeout将执行放在摘要周期的末尾:

console.log(element.find("view").length); // will output 0
$timeout(function(){
  console.log(element.find("view").length); // will output 1
});

不过,这不是一个好的解决方案。如果指令的用户决定动态加载内容,例如使用ng-include,则会中断。因此,如果需要下载模板,则即使使用$timeout,以下也无效

<swapview>
   <div ng-include="'templateForViews.html`"></div>
<swapview>

那么,什么有效?

处理预期的子指令的正确方法是让子指令向父控制器注册require: "^parent"的控制器:

.directive("swapview", function($timeout){
  return {
    controller: function(){
      var childViewCtrls = [];

      this.registerView = function(view, viewEl){
        childViewCtrls.push({ctrl: view, elem: viewEl});
      };
    },
    link: function(scope, element){
      //
    }
  };
})

.directive("view", function($timeout){
  return {
    require: ["view", "^swapview"],
    controller: function(){
      // useful to expose an API
    },
    link: function(scope, element, attrs, ctrls){
      var me = ctrls[0],
          swapview = ctrls[1];

      swapview.registerView(me, element);
    }
  };
});