为什么AngularJS指令编译不支持嵌套指令

时间:2013-08-23 06:26:16

标签: angularjs

根据我的理解,$ compile应该能够支持嵌套的指令编译/链接,但是我们遇到了一个问题,即编译/链接是不完整的 - 只有最外层的指令被渲染到DOM中,并且只有在以下条件属实:

  1. 内部指令模板通过templateUrl加载(例如异步方式)
  2. 在Angular上下文之外触发编译。
  3. 我写了一个jsfiddler来演示它,下面列出了部分代码,完整案例http://jsfiddle.net/pattern/7KjWP/

    myApp.directive('plTest', function($compile){
    return {
        restrict :'A',
        scope: {},
        replace: true,
        template: '<div>plTest rendered </div>',
        link: function (scope, element){
            $('#button1').on('click', function(){
                var ele;
                ele = $compile('<div pl-shared />')(scope); 
                console.log('plTest compile got : '+ ele[0].outerHTML);
               // scope.$apply();
                element.append(ele);
            });
         }
    };
    });
    
    myApp.directive('plShared', function($compile, $timeout){
    return {
        restrict: 'A',
        scope: {},
        replace: true,
        link: function (scope, element){
            // comment out below line to make render success
            //$timeout(function(){});
            var el = $compile('<div pl-item></div>')(scope);
            console.log('plShared compile got:' + el[0].outerHTML);
            element.append(el);
        }
    };
    });
    
    myApp.directive('plItem', function($timeout){
    return {
        restrict: 'A',
        scope:{},
        template:'<div>plItem rendered <div pl-avatar/></div>',
        link: function(scope){            
    
        }
    };
    });
    
    myApp.directive('plAvatar', function(){
    return {
        restrict: 'A',
        scope: {}
       , templateUrl: 'avatar.html'
      //  ,template: 'content of avatar.html <div pl-image></div>'
    };
    });
    

    有趣的是,我可以通过调用scope来解决这个问题。$ apply()在compile()调用之后的某个地方(第27行) 或者将$ timeout(function(){})调用添加到内部指令(第41行)之一的链接函数中。这是缺陷还是设计?

2 个答案:

答案 0 :(得分:3)

$(foo).on(bar, handler)是一个jQuery事件,这意味着AngularJS不知道它的具体细节,并且在它处理所有绑定之后不会(不能)运行apply-digest cycle

scope.$apply是为此而做的,正如你正确地说的那样,修复它。经验法则是:如果您使用其他库在AngularJS应用程序中实现UI功能(特别是:在apply-digest循环之外),您必须自己调用scope.$apply

HTH!

答案 1 :(得分:0)

在element.append(el)之后,尝试再次编译,因为刚刚修改了DOM。

您可以尝试使用$compile(element)(scope);$compile(element.contents())(scope);等内容。

如前所述,我还会更改事件处理程序,如下所示:

$('#button1').on('click', function(){
     scope.$apply( function(){
          //blablalba
     });
});

另外,如果您想要缩小代码,请提供一些建议,我将使用以下语法声明编译依赖项:

.directive('directiveName',['$service1',''$service2,...,'$compile', function($service1, $service2,...,$compile){
     //blablabla
}]}