【问题标题】:AngularJS: multiple directives with transclusion on same elementAngularJS:在同一元素上包含多个指令
【发布时间】:2013-05-01 12:55:35
【问题描述】:

我正在尝试将 2 个模板注入一个元素并对其进行操作:

<div
  ic-first="foo"
  ic-second="bar"
  ic-third="baz"
  ic-fourth="qux"
>
</div>

icFirst 应该通过模板注入一个空 div 作为其元素的子元素。 icSecond 应该注入第二个 div(带有一堆内容)作为其元素的第二个子元素,因此生成的 html 如下所示:

<div
  ic-first="foo"  // priority: 100
  ic-second="bar" // priority: 50
  ic-third="baz"  // priority: 0
  ic-fourth="qux" // priority: 0
>
  <div id="foo"></div>
  <div> <!-- a bunch of stuff from the templateUrl --> </div>
</div>

icFirsticSecond 都会将其他元素注入到新创建的容器中。

当我在两个指令上指定指令模板属性时,我得到一个错误:

错误:多个指令 [icFirst, icSecond] 要求模板在:&lt;div ic-first...

当我将transclude: true 添加到两个指令时,icFirst 执行得很好……但是同一元素上的其他指令不会执行。当我设置transclude: 'element' 时,其他指令会执行我收到一个错误,即第一个孩子 ($scope.firstObj) 未定义。

所有四个指令都需要访问彼此的范围,所以我的大部分工作都在它们的控制器中完成:

app.directive('icFirst', ['ic.config', function (icConfig) {
  return {
    restrict: 'A',
    priority: 100,
    template: '<div id="{{firstId}}"></div>',
    replace: false,
    transclude: 'element',
    controller: function icFirst($scope, $element, $attrs) {
      // …
      $scope.firstId = $scope.opts.fooId;
      $scope.firstElm = $element.children()[0];
      $scope.firstObj = {}; // this is used by the other 3 directives 
    },
    link: function(scope, elm, attrs) { … } // <- event binding
  }
);
app.directive('icSecond', ['ic.config', function (icConfig) {
  return {
    restrict: 'A',
    priority: 0,
    templateUrl: 'views/foo.html',
    replace: false,
    transclude: 'element',
    controller: function icSecond($scope, $element, $attrs) {
      // …
      $scope.secondElm = $element.children()[1];
      $scope.secondObj = new Bar( $scope.firstObj );
      // ^ is used by the remaining 2 directives & requires obj from icFirst
    },
    link: function(scope, elm, attrs) { … } // <- event binding
  }
);

注意我已更正 replace: false 的行为以匹配记录在案的行为,如拉取请求 #2433 中所述。

我尝试在控制器中实例化$scope.firstObj,并将其设置在linkFn 中(希望在linkFn 执行时嵌入已经完成),但我遇到了同样的问题。看来 first-child 实际上是一条评论。

【问题讨论】:

    标签: javascript html angularjs angularjs-directive


    【解决方案1】:

    我能想出解释抛出此错误的唯一原因是 AngularJS 团队试图避免不必要的覆盖/DOM 操作:

    考虑到replace: false 的实际行为与记录的行为,我认为实际行为实际上是预期的行为。如果这是真的,那么允许在同一个元素上使用多个模板/templateUrls 将导致后续模板覆盖以前的模板。

    由于我已经修改了源代码以匹配记录的行为,作为快速修复,我再次修改了源代码 (/src/ng/compile.js:700) 以删除 assertNoDuplicate 检查(对应于 @ 987654324@)。现在我返回以下 2 个对象,它可以工作,我找不到任何负面影响:

    // directive icFirst
    return {
      restrict: 'A',
      priority: 100,
      replace: false,
      template: '<div id="{{firstId}}"></div>',
      require: ["icFirst"],
      controller: Controller,
      link: postLink
    };
    // directive icSecond
    return {
      restrict: 'A',
      require: ['icFirst'],
      replace: false,
      templateUrl: 'views/bar.html',
      priority: 50,
      controller: Controller,
      link: postLink
    };
    

    如果设为永久,支票可能应该是
    if (directive.templateUrl &amp;&amp; directive.replace)
    (对于directive.template 也类似)

    【讨论】:

    • 现在有一种更简单的方法。只需将$$tlb: true 添加到您的指令中,它就会绕过断言。
    • @JonathanRowny $$ 表示$$tlb 是 API 的“私有”,不应在 API 之外使用,因为开发人员可能会决定随时破坏它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-03
    • 2013-09-04
    • 1970-01-01
    • 2014-03-21
    • 2017-09-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多