Angular:从父指令获取模板URL

时间:2014-11-07 22:46:57

标签: javascript angularjs templates angularjs-directive angularjs-scope

据我所知,我可以根据选项DOM属性template-url="foo.html"动态设置templateUrl,给出以下代码:

angular.module('foo').directive('parent', function() {
   return {
       restrict: 'E',
       link: function(scope, element, attrs) {
           // code
       },
       templateUrl: function(elem,attrs) {
           return attrs.templateUrl || 'some/path/default.html'
       }
   }
});

但是,我需要更进一步,将这个字符串更深一层地传递给子指令。

鉴于此HTML:

主项目中的用法

<parent parent-template="bar.html" child-template="foo.html"></parent>

在大多数情况下,子项不会公开,因此如果设置了child-template,则需要隐式替换位于父templateUrl中的所有子<child></child>元素foo.html 1}}。

require: '^parent'属性将数据从范围传递到范围,但我在templateUrl声明时没有看到它。

foo.html

<h1>Title</h1>
<child ng-repeat="item in array"></child>

指令

angular.module('foo').directive('parent', function() {
   return {
       restrict: 'E',
       link: function(scope, element, attrs) {
           // code
       },
       templateUrl: function(elem,attrs) {
           return attrs.parentTemplate || 'some/path/default.html'
       },
       scope: {
          childTemplate: '=childTemplate'
       }
   }
})
.directive('child', function() {
   return {
       restrict: 'E',
       link: function(scope, element, attrs) {
           // code
       },
       templateUrl: function(elem,attrs) {
           return ??? // parent.attribute.childTemplate? || 'some/path/default.html'
       },
       require: '^parent',
       scope: {
          childTemplate: '=childTemplate'
       }
   }
});

2 个答案:

答案 0 :(得分:1)

更新

旧的答案(见下文)不起作用,因为它只能访问link函数内所需指令的控制器,templateUrl函数得到在link函数之前执行。

因此,解决此问题的唯一方法是处理子指令的templateUrl函数中的所有内容。但是this function only takes 2 arguments: tElement and tArgs

因此,我们必须找到父指令的元素并访问属性child-template。像这样:

angular.module('testApp', [])
.directive('parent', function() {
   return {
       restrict: 'E',
       link: function(scope, element, attrs) {
       },
       transclude:true, 
       templateUrl: function(elem,attrs) {
           return attrs.parentTemplate || 'default.html'
       }
   }
})
.directive('child', function() { 
   return {
       restrict: 'E',
       require:'^parent',
       templateUrl: function(elem,attrs) {
           //if jQuery is loaded the elem will be a jQuery element, so we can use the function "closest"
           if(elem.closest) 
              return elem.closest("parent").attr("child-template") || 'default.html';

           //if jQuery isn't loaded we will have to do it manually
           var parentDirectiveElem=elem; 
           do{
             parentDirectiveElem=parentDirectiveElem.parent();
           }while(parentDirectiveElem.length>0 && parentDirectiveElem[0].tagName.toUpperCase()!="PARENT");
           return parentDirectiveElem.attr("child-template") || 'default.html'; 
       }
   }
});

Example

旧答案

由于你正在隔离范围,你可以试试这个,它有点hacky但我想它应该有效:

angular.module('foo').directive('parent', function() {
   return {
       restrict: 'E',
       controller:  function($scope) {
           this.childTemplate=$scope.childTemplate;
       },
       link: function(scope, element, attrs) {

       },       
       templateUrl: function(elem,attrs) {
           return attrs.parentTemplate || 'some/path/default.html'
       },
       scope: {
          childTemplate: '@'
       }
   }
})
.directive('child', function() {
   return {
       restrict: 'E',
       require: '^parent',
       link: function(scope, element, attrs, parentController) {
           if(parentController.childTemplate)
               element.data("childTemplate", parentController.childTemplate);
       },
       templateUrl: function(elem,attrs) {
           return elem.data("childTemplate") || 'some/path/default.html'
       }
   }
});

答案 1 :(得分:0)

在我的问题中,我试图为没有一个现成指令的templateUrl提供覆盖。我原来的问题没有提到这一点,但是,我想把这个作为对我可能已经忘记的其他人的参考。 Angular允许您修饰指令并覆盖它们的属性。

app.config(function($provide) {
  $provide.decorator('child', function($delegate) {
    var directive = $delegate[0];

    directive.templateUrl = 'path/to/custom.html';
    return $delegate;
  });
});