在不两次编译子节点的情况下用另一条指令替换指令

乙炔

在一个项目中,我建立了一个指令aDir该指令在其后链接函数中使用$ compile替换为另一个bDir它为bDir创建一个“快捷方式”,这很有用,因为bDir有很多参数,我在整个项目中都使用了它。

在我的模板中:

<p>
    <button a-dir></button>
</p>

编译在:

<p>
    <button b-dir arg1="" arg2="" ... ></button>
</p>

像这样的代码非常有用:

function aDir($compile){
  return {
    restrict: 'A',
    link: function(scope, iElem, iAttrs){
      iElem.attr('b-dir', '');
      iElem.attr('arg1', '');
      iElem.attr('arg2', '');
      [...]
      iElem.removeAttr('a-dir'); // To avoid infinite loop
      $compile(iElem)(scope);
    }
  }
}

但是,如果应用aDir的元素有子元素,则它们将被编译两次。一次是$compile由Angular启动函数,一次是由$compile函数在Dir后链接中调用

考虑一下这个矮子这是HTML:

<outer-level>
  <p replace-by-another>
    <inner-level>Hello World!</inner-level>
  </p>
</outer-level>

replaceByAnother替换为另一个指令externalLevelinnerLevel是指令,它们的编译,前置和后置链接功能被调用时,除了登录控制台外,什么也不做。

控制台日志为:

outerLevel: compile
replaceByAnother: compile
innerLevel: compile
outerLevel: pre link
replaceByAnother: pre link
innerLevel: pre link
innerLevel: post link
replaceByAnother: post link
    another: compile
    innerLevel: compile
    another: pre link
    innerLevel: pre link
    innerLevel: post link
    another: post link
outerLevel: post link

因此,我们有两次调用innerLevel的compile,pre link和post link函数就我而言,这完全可以,但是我有兴趣完全了解$compile它的作用以及是否可以避免这种行为。

我通过在replaceByAnother指令中定义一个编译函数来尝试了几件事,但我只是设法更改了执行顺序,而不是只对一次innerLevel指令进行编译

http://plnkr.co/edit/ZnBRaskb1WPkRZv36giS

function replaceByAnother($compile){
  return {
    restrict: 'A',
    compile: function(tElem, tAttrs){
      console.log('replaceByAnother: compile');
      tElem.attr('another', '');
      tElem.removeAttr('replace-by-another');
      var anotherLinkFunc = $compile(tElem);

      return {
        pre: function(scope, iElem, iAttrs){
          console.log('replaceByAnother: pre link');
        },
        post: function(scope, iElem, iAttrs){
          console.log('replaceByAnother: post link');
          anotherLinkFunc(scope);
        }
      }
    }
  }
}

结果:

outerLevel: compile
replaceByAnother: compile
  another: compile
  innerLevel: compile
innerLevel: compile
outerLevel: pre link
replaceByAnother: pre link
innerLevel: pre link
innerLevel: post link
replaceByAnother: post link
  another: pre link
  innerLevel: pre link
  innerLevel: post link
  another: post link
outerLevel: post link

你有什么主意吗?

有了@georgeawg和@AndrésEsguerra的答案,我找到了一个令人满意的解决方案:

  • 使用terminal: true高优先级来防止Angular编译两次子节点。
  • 在编译功能中修改模板元素并对其进行调用$compile存储的输出$compile
  • 在链接函数中调用此输出以将模板元素绑定到作用域。

function replaceByAnother($compile){
  return {
    restrict: 'A',
    terminal: true,
    priority: 100000,
    compile: function(tElem, tAttrs){
      tElem.attr('another', '');
      tElem.removeAttr('replace-by-another');
      var anotherLinkFunc = $compile(tElem);

      return {
        pre: function(scope, iElem, iAttrs){
          // pre link
        },
        post: function(scope, iElem, iAttrs){
          anotherLinkFunc(scope, function cloneAttachedFn(clone) {
              iElem.replaceWith(clone);
          });
        }
      }
    }
  }
}
乔治

您可以通过tElem在编译阶段将其内部清空并清空来避免第一次内部编译

//replaceByAnother Directive
function replaceByAnother($compile){
  return {
    restrict: 'A',
    compile: function(tElem, tAttrs){
      console.log('replaceByAnother: compile');
      //clone tElem
      var tClone = tElem.clone();
      //empty tElem
      tElem.empty();
      return {
        pre: function(scope, iElem, iAttrs){
          //console.log('replaceByAnother: pre link');
        },
        post: function(scope, iElem, iAttrs){
          //console.log('replaceByAnother: post link');
          //modify and compile cloned elements
          tClone.attr('another', '');
          tClone.removeAttr('replace-by-another');
          var linkFn = $compile(tClone);
          linkFn(scope, function transclude(clone) {
              iElem.append(clone);
          });
        }
      }
    }
  }
}

然后在postLink阶段修改和编译克隆的元素。

PLNKR上演示

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

汇编OFFSET在一条指令中使用了两次,什么是offset的offset?

如何在不递归的情况下两次调用同一函数

如何使LLVM优先使用一条机器指令而不是另一条机器指令?

如何在不询问输入两次的情况下将一个函数的输入传递给另一个函数?

如果后面有另一条指令,Kivy不添加小部件

仅在第二条记录存在的情况下,两次连接到同一表

有没有办法在不编写两次左连接子查询的情况下脱身?

一条语句中有两次Bash替换?

等待上一条指令是否有用

我如何在不停顿的情况下处理上一条ALU指令上的分支的MIPS?

printf两次打印同一条语句

react无法在不刷新页面的情况下两次使用fileinput

Angular 2-如何在不两次渲染子组件的情况下将数据传递给子组件?

返回上一条指令js

如何禁用一条指令的中断?

如何获得给定指令的下一条即时指令?

指令点击两次被调用

如何在不执行Express Js Promise中的下一条语句的情况下从.then()进行转义?

现代C ++编译器是否可以避免在某些情况下两次调用const函数?

为什么数组不采用先前指令的值,而只采用最后一条指令的值?

如何在不两次指定符号位置的情况下围绕符号中心旋转符号?

如何在不键入两次公式的情况下将否定结果设置为零

如何在不执行两次SQL调用的情况下计算SQL列中特定值出现的次数

如何在不构建解决方案两次的情况下运行单元测试和部署代码?

是否可以不执行一条指令就退出RUNNABLE状态?

还有另一条与MOVZX类似但在8086上受支持的指令吗?

默认情况下,一次为配置文件执行两次Maven复制资源

我们如何在不更改变量名称的情况下用另一个相同长度的向量替换 tibble 中的列?

Excel-如何检查某个值是否在一列中出现两次并将其与另一条件进行比较