【问题标题】:Angular: get Template URL from parent directiveAngular:从父指令获取模板 URL
【发布时间】:2014-11-07 22:46:56
【问题描述】:

我知道我可以根据选项 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,则需要隐式替换所有位于父foo.html中的子<child></child>元素的templateUrl

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'
       }
   }
});

【问题讨论】:

  • 我刚刚对您的代码进行了编辑,请确保我更改的内容正确(您将第二个指令命名为parent,就像第一个指令一样,我认为您希望这样命名为child)。谢谢!
  • 没错。复制/粘贴错误,谢谢!
  • 附加到child 指令范围的childTemplate 是否有可能覆盖父级的范围?

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


【解决方案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'
       }
   }
});

【讨论】:

  • 您可能需要 $watch 子指令的 childTemplate 才能使其工作。
  • @dopatraman 您的意思是父指令,对吗?是的,这是个好主意,我要更新代码。感谢您的反馈!
  • @dopatraman 我已经更新了代码,但问题是,如果属性 childTemplate 的值在父项中发生更改,那么我可以观察该更改并更新控制器。 .但是,在孩子中我不能添加观察者,因为它是在父母的控制器中设置的,而且你只能在范围内有观察者......也许我可以尝试观察,但这似乎有点太很多,所以我认为我会通过,因为他们似乎不太可能想要解释这一点。
  • 谢谢@Josep,我对你在child 指令的link: fn() 中使用parentController 感到困惑。 parentController 不是对child 指令的控制器的引用吗?至少在测试你的代码时,它对我来说是这样的。
  • @Brian parentController 是对父指令控制器的引用,请注意我使用的是require: '^parent',因此在这种情况下,您在link 函数中获得的控制器是父母的控制器。
【解决方案2】:

在我的问题中,我试图为没有的现成指令的templateUrl 提供覆盖。我最初的问题没有提到这一点,但是,我想将其添加为对可能已经忘记的其他人的参考,就像我一样。 Angular 允许你装饰指令并覆盖它们的属性。

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

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

【讨论】:

    猜你喜欢
    • 2015-12-09
    • 2016-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-22
    • 2015-11-01
    • 1970-01-01
    相关资源
    最近更新 更多