angularjs - 替换 :true for angularJS directives 的替代方法

标签 angularjs

所以 replace: true 将在不久的将来从 AngularJS 中删除。我明白为什么,但我认为在 AngularJS 中进行开发的某些场景没有它就无法得到很好的支持。

我想创建一个如下所示的按钮组件:

<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 包装器,由于前端限制,这是 Not Acceptable 。

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

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

最佳答案

首先,我不认为 replace: true 在不久的将来会被删除。它已被弃用,但在任何 Angular 1.X 版本中删除它都将是一个重大变化,所以我认为在 Angular 2.0 发布之前你没问题。 Angular 2.0 的破坏程度远不止这些,所以我不会太担心如何让现有的应用程序在没有替换的情况下工作:true。 2.0 可能会有某种等效的功能,但将现有应用程序迁移到 2.0 可能不是您想要做的事情。

但是,假设回答您的问题:

replace: true 做了两件事:

1) 它用指令模板替换 DOM 中的元素。

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

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

例如,如果您的元素是:

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

并且 someDirective 有一个模板:
<div ng-click="doSomethingInDirective()"></div>

更换节点后哪个优先? replace: true 的逻辑当前会做出这些决定,并为您安排好一切。

如果由于某种原因,replace: true 从 1.X 中删除(它不会),你会怎么做?

答案是您必须手动执行 replace: true 现在所做的操作,(简化)为:

1) 获取原始元素的属性

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

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

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

4a) 如有必要,执行转置(转置: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);

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

关于angularjs - 替换 :true for angularJS directives 的替代方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28822194/

相关文章:

html - 如何找出打开了多少层?

javascript - 在 ng-repeat 中使 ng-disabled 为真

javascript - 如何使用 angularjs 工厂获取和设置?

javascript - 如何在我的 Angular 代码中使用 angular-sortable-view?

angularjs - 使用 blueimp 插件和 AngularJS 通过单个文件上传重置文件选择

angularjs - Angular 1.5 Material 快速拨号在 table 上预留空间

javascript - 我如何检测是否使用 angular.forEach AngularJS 添加了一个对象

javascript - AngularJS,如何在 select > options 上使用 min =""来验证表单?

jquery - 使用列 View ext 时是否可以设置 fancyTree 的高度

javascript - AngularJS 中的自定义排序