2015-03-03 79 views
4

因此,替换:在不久的将来,将从AngularJS中删除true。我明白为什么,但我认为在AngularJS中开发的某些场景没有它可以得到很好的支持。替代替代:对于angularJS指令为true

我想创建一个按钮组件,看起来像这样:

<button ng-click="doSomething()" important-model="outerCtrl.theModel"> 
    important text 
</button> 

即从属性开始,例如,像这样:

<div my-button-component> 
</div> 

现在使用替代我得到了我想要,但由于它已被弃用,我想避免使用它,所以我认为也许我可以这样做:

<button my-button-component ng-click="doSomething()" important-model="outerCtrl.theModel"> 
</button> 

让指令在里面插入'重要文本'。

这个解决方案很奇怪,因为虽然ng-click可以访问指令范围,并且可以像预期的那样工作(就好像它在指令模板中一样),但是我的组件是一个按钮并且是可点击的,否则应该在我的组件内部定义,而不是在我选择使用它的模板中。

另一种选择是只有一个div包装所有这一点,由于前端约束,这是不可接受的。

最后一个选择是接受我无法使用指令控制根元素的类型或属性,并且在程序中应用点击侦听器和任何其他行为(例如ng-class)。这对我来说似乎不是一个好的解决方案,但它可能是迄今为止最好的解决方案。

这不是我第一次觉得你对指令的根元素有多少控制有些问题,我是否在想这个错误?

回答

6

首先,我不认为替换:在不久的将来,真正被删除。它已被弃用,但在任何角度1.X版本中摆脱它将是一个突破性的改变,所以我认为你没事,直到发布Angular 2.0。 Angular 2.0将打破更多,所以我不会太担心如何让现有的应用程序工作,而不需要更换:true。很可能2.0会具有某种等效的功能,但将现有的应用程序迁移到2.0可能不是您想要做的事情。

然而,假设回答你的问题:

取代:真正做了两两件事:

1)替换元素与指令模板的DOM。

2)它将DOM中元素的属性与指令模板合并。

(2)实际上是该特征的非平凡部分,它周围的边缘情况是Angular团队想要摆脱它的原因。

举例来说,如果你的元素是:

<div some-directive ng-click="doSomething()"><div> 

而且someDirective有一个模板:

<div ng-click="doSomethingInDirective()"></div> 

你已经更换了节点之后的优先级? replace:true的逻辑当前会做出这些决定并为您提供一切。

如果出于某种原因将其替换为:真正从1.X中删除(它不会),那么你会怎么做?

答案是,你将不得不手工做的替换:真正做现在,这(简体)是:

1)获取的原始元素的属性

2)合并的原始元素与属性指令模板,跟踪不是指令和属性的属性,并且跟踪每个指令的声明位置(在原始元素或模板中)。

3)通过编译合并的属性指令和指令模板指令来编译指令模板。

4)将作为原始元素一部分的合并属性指令链接到$ parent作用域,并将所有其他指令链接到指令作用域。链接指令该指令范围

4A)如果必要的话(transclude执行transclusion:true和模板包括NG-transclude)

5)替换为完全挂钩指令模板原始元素。

这里是从GitHub的相关代码:

if (directive.replace) { 
      replaceDirective = directive; 
      if (jqLiteIsTextNode(directiveValue)) { 
       $template = []; 
      } else { 
       $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue))); 
      } 
      compileNode = $template[0]; 

      if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) { 
       throw $compileMinErr('tplrt', 
        "Template for directive '{0}' must have exactly one root element. {1}", 
        directiveName, ''); 
      } 

      replaceWith(jqCollection, $compileNode, compileNode); 

      var newTemplateAttrs = {$attr: {}}; 

      // combine directives from the original node and from the template: 
      // - take the array of directives for this element 
      // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed) 
      // - collect directives from the template and sort them by priority 
      // - combine directives as: processed + template + unprocessed 
      var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs); 
      var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1)); 

      if (newIsolateScopeDirective) { 
       markDirectivesAsIsolate(templateDirectives); 
      } 
      directives = directives.concat(templateDirectives).concat(unprocessedDirectives); 
      mergeTemplateAttributes(templateAttrs, newTemplateAttrs); 

我不会出去,很快写自己,任何时候的版本。任何需要替换的代码:true也需要Angular 1.X,所以它会被支持。当你准备用Angular 2.0写一个新的应用程序时,会有另一种(希望更好)的方式来做到这一点。

2

听起来和你一样,在这种情况下应该使用指令元素,而不是指令属性。

按照该guidance from the Angular docs,使用元素,当你想创建可重用的组件,而当你要增加的东西的行为属性:

使用,当你创建一个组件,它是一个元素控制模板。常见的情况是当您为模板的某些部分创建特定于域的语言时。在使用新功能装饰现有元素时使用属性。

当你使用一个指令元素没有replace: true

<my-button-component example-attr="example"></my-button-component> 

将输出:

<my-button-component example-attr="example"> 
    <button ng-click="doSomething()" important-model="outerCtrl.theModel"> 
     important text 
    </button> 
</my-button-component> 

<my-button-component>标签没有意​​义的浏览器,这样就不会影响到文档流或造型。

在该指令,你还是吐出相同<button> HTML,你仍然有机会获得通过像example-attr属性传入的值,所以是不是真的在所有replace: truereplace: false多大区别。

+0

“标签对浏览器没有任何意义”......但不幸的是它对其他指令有意义。例如,标签内的任何内容都不再可用于Angular的表单验证。所以有一个坚实的用例来“替换”。 transclude是否提供相同的功能? – 2015-07-09 01:44:23

+0

“..对浏览器没有意义..”,取决于你所指的意义。我遇到了指令元素缠绕标签并因此使用替换的问题。如果你在之外有任何非表元素(table或thead,tbody等)的元素,那么你的行不能正确呈现。 – 2016-01-17 01:11:38

+0

它也不会做属性合并,这对于我制作包装文件输入的组件时非常重要。 – Thayne 2016-04-29 23:44:39