【问题标题】:Can I use arbitrary AngularJS directives inside other directives?我可以在其他指令中使用任意 AngularJS 指令吗?
【发布时间】:2014-11-07 20:13:30
【问题描述】:

我想使用指令显示来自我的控制器的对象列表。在该指令中,我希望能够使用几个可能的指令之一,但我并不总是知道是哪一个。如果我在控制器的范围内设置该指令名称,我如何在主指令的模板中使用它?

这是plnkr,下面是什么。

HTML:

<div ng-app="music" ng-controller="rock">
  <h1>Favorite Bands</h1>
  <prog></prog>
</div>

JS:

angular.module('music', []);

angular.module('music').controller('rock', ['$scope', function($scope){
  $scope.directiveName = 'dinosaurs';
  $scope.bands = [
    { name:'Rush'}, { name:'King Crimson' }, { name: 'Porcupine Tree'}, { name: 'Marillion'}];
}]);

angular.module('music').directive('prog', function(){
  return {
    restrict: 'E',
    replace: true,
    template: '<ul><li ng-repeat="band in bands"><{{directiveName}}>{{band.name}}</{{directiveName}}></li></ul>'
  };
});

angular.module('music').directive('dinosaurs', function(){
  return {
    restrict: 'E',
    transclude: true,
    template: '<ng-transclude></ngtransclude> - DINOSAUR!'
  };
});

在这种情况下,我将$scope.directiveName 设置为dinosaurs,这是我想在主指令中使用的指令的名称,称为prog

prog 的模板中,我尝试使用插值将指令的名称插入括号中。然而,输出如下:

  • 拉什
  • 深红之王
  • 豪猪树
  • Marillion

我也尝试在 span: 上使用类名,并将“恐龙”作为一个类插入到 span 中,但 Angular 不会将其作为指令处理。

我不确定我是否需要隔离范围,但从我所读到的内容来看,我认为这无关紧要。我也是嵌入的新手,但我认为dinosaurs 指令应该获取每个列表项的内容并添加“ - DINOSAURS!”到最后。

将一个指令的名称传递给另一个指令的最佳实践方法是什么?

【问题讨论】:

  • 我一直在关注docs.angularjs.org/guide/directiveDan Wahlin's posts on directives。几个主题,如this one 地址指令在其他指令中,但不传递这些指令的名称。
  • 如果你先声明恐龙指令,有帮助吗?
  • @dandavis - 不错的想法,但显然不是。我在 plnkr 上试过了,但没有运气。
  • 可以使用链接功能连接到父指令控制器-function(scope, el, attr, ctrl)

标签: javascript angularjs


【解决方案1】:

为了避免混乱的$compiles,我会做的是使用ng-include 作为开关,比如this

angular.module('music').directive('prog', function(){
  return {
    restrict: 'E',
    replace: true,
    template: '<ul><li ng-repeat="band in bands"><div ng-include="directiveName + \'.html\'"></div></li></ul>'
  };
});

【讨论】:

  • 到目前为止肯定很有希望 - 我已经让它在原则上工作,只需要解决一些语法问题。谢谢!
【解决方案2】:

一种可能的解决方案是将“我如何渲染这个项目”的责任从控制器/指令转移到项目本身。

最简单的方法是给项目一个 templateUrl 属性。然后,您可以引入一个简单的包装器指令来绑定项目:

myModule.directive('bandView', function() {
  return {
    scope: {band: '=bandView'}
    templateUrl: '<div ng-include="band.templateUrl"></div>'
  };
});

然后,如果你有一些波段列表,你可以渲染它们:

<h1>My band list</h1>
<div ng-repeat="b in bands" band-view="b"></div>

然后,对于您想要执行的每种渲染类型,您将拥有不同的 html 模板。

这个想法正在运行:http://jsbin.com/EhAnIMaJ/2/edit?html,js,output

【讨论】:

  • 感谢您的回答。 TemplateCache 的东西很酷——我不知道。如果我理解正确,这根本不会有嵌套指令,只是基于 url 属性执行不同包含的指令。有道理。
  • 是的——在我的示例中使用 $templateCache 只是为了演示在 jsbin 中使用不同的模板文件。在实际应用中,您很可能需要单独的模板文件。
【解决方案3】:

更新 - 指令中有几个选项可以更改模板:

最简单的第一个想法是template:function(el, attr),它允许您返回一个函数,使您能够根据non-interpolated 属性更改模板。所以它可能无法满足您的需求。

template:function() plunker,

另一种方法是 $compile 模板并在链接函数中替换 you 元素。

$compile plunker


这与多模板无关 -

您可以在链接函数中到达父指令的控制器并在其中维护范围。 这是尝试将其简化为基本要素:

app.directive("parentDirective", function() {
  return {
    restrict: 'EA',
    controller: function($scope) {
        this.callFunc = function(){
           ...
        }
    }
  }
});

app.directive("childDirective", function($compile, $log) {

  return {
    require: '?^parentDirective',
    scope: {
       model: '=ngModel'
    },
    link : function(scope, el, attr, ctrl) {
        ctrl.callFunc();
    }
...

和类似的plunkerplunker

【讨论】:

  • 对不起,如果我遗漏了一些明显的东西,但这有什么帮助?我目前在父级上没有控制器,但也许我需要一个。我正在寻找在 parentDirective 中识别 childDirective 的方法。如果 callFunc() 会处理这个问题,模板将如何使用它?感谢您的回复!
  • 也许我误解了,因为指令的最佳实践是声明性的,所以 ` 并没有完全声明很多,我想说将你的子元素添加到html,但是 - 它看起来更像是您的意图是使用多个指令通过主控制器中的 $scope.variable 替换模板?
  • 是的, 并不是所有的声明性 - 我猜是简化的受害者。实际情况是我正在使用一个树网格指令,该指令接受具有数据和层次结构的对象。在某些情况下,网格中的列应该是带有值的只读列,而在其他情况下,它应该具有更改值的控件。改变值的控制是我试图作为指令插入的。
  • 如果我使用一个我也可以在不进行插值的情况下访问的配置对象,模板函数可能会起作用。我仍在学习隔离范围以及编译和链接阶段,您的简单示例很有帮助。非常感谢您的更新。
猜你喜欢
  • 2020-06-24
  • 2015-02-07
  • 2015-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多