AngularJS:在同一元素上进行转换的多个指令

时间:2013-04-18 00:24:51

标签: javascript html angularjs angularjs-directive

我正在尝试将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>

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

当我在两个指令上指定指令模板属性时,出现错误:

  

错误:多个指令[icFirst,icSecond]要求提供模板:<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执行时完成转换),但是我遇到了同样的问题。看起来第一个孩子实际上是一个评论。

1 个答案:

答案 0 :(得分:2)

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

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

由于我已经修改了源以符合记录的行为,因此作为快速修复,我再次修改了源(/src/ng/compile.js:700)以删除assertNoDuplicate检查(对应于angular.js:4624)。现在我返回以下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 && directive.replace)
(和directive.template类似)