【问题标题】:recompiling angular directive to add ng-module and ng-change programmatically重新编译 Angular 指令以编程方式添加 ng-module 和 ng-change
【发布时间】:2013-11-18 08:43:37
【问题描述】:

我想知道我做的是否正确。

序言: 我开发了一个 Typeahead 类,它消耗资源并将结果存储在自身中。该类或多或少具有以下结构:

  • 输入:存储搜索文本的位置。
  • 列表:存储结果的位置。
  • change:每次输入更改时执行的函数。
  • 光标:跟踪当前悬停/选定元素的函数。

问题是,如果我想将所有必需的属性附加到输入,代码看起来很臃肿:

<input 
  type="text"
  ng-model="myTa.input"
  ng-change="myTa.change();"
  ng-keyup="myTa.cursor()"
  .... 
/>

我想要完成的是一个只需要 Typeahead 实例的指令,它会自动将所有必需的属性附加到元素。例如:

<input type="text" my-typeahead="myTa" />

在继续之前,我想明确以下几点:

  • 我不想使用 template 或 templateUrl,因为我想让指令非常灵活,让它附加到输入、文本区域、选择甚至链接。
  • 我不想使用 attrs.$observe 或 scope.$watch,因为 ng-model 的工作非常出色,并且完成了我想要的工作。
  • 我知道根元素中的新元素无需任何技巧即可编译,但父元素本身不会编译新指令。 (这是有道理的)

现在,如果我这样做,我会在地狱中燃烧吗:

angular
.module('myTypeaheadDirective', [])
.directive('myTypeahead', function($compile, $rootScope) {
    return {
        restrict: 'A',
        scope: {
            typeahead: '=myTypeahead'
        },
        compile: function() {
            return {
                pre: function precompile(scope, element, attrs) {
                    var installedAttribute = 'my-typeahead-installed';

                    if ( angular.isUndefined( element.attr( installedAttribute ) ) ) {
                        element.attr('ng-model', 'typeahead.input');
                        element.attr('ng-change', 'typeahead.change()');
                        element.attr( installedAttribute, true );
                        $compile(element)(scope.$parent);
                    }
                }
            }
        }
    }
});

解释代码:

指令预编译过程检查是否已经安装,否则会进入死循环。

在条件中,我根据需要添加任意数量的指令。

请注意,我使用的是 ng-model="typeahead.input" 但这是一个独立的范围,因此我可以有多个输入具有不同的 typeahead 实例。

附加新指令后,我使用 $compile 服务使用父作用域重新编译元素(因此它可以访问原始 typeahead 实例)。

我的问题是:

  • 我在这里做什么很幼稚?
  • 有没有更好的方法来做到这一点?
  • 重新编译元素会导致性能问题吗?
  • 以这种方式访问​​父作用域会导致问题吗?

非常感谢您抽出宝贵时间:)

【问题讨论】:

    标签: javascript angularjs angularjs-directive


    【解决方案1】:

    由于您传递到隔离作用域的内容可以很容易地从属性值中使用...可以删除隔离作用域,然后指令作用域将是父作用域。

    仅从属性中设置 typeahead 对象:

    var typeahead= attrs.myTypeahead;
    element.attr('ng-model', typeahead+'.input');
    

    【讨论】:

    • 这个方法我也试过了,还是不行。造成这种情况的主要原因是angular不关注编译过程后添加到元素中的任何ng-model、ng-change等。为了解决这个问题,我像你一样添加了 ng-model attr,然后使用 $compile(element, scope) 重新编译了元素。我不需要使用 typeahead+'.input',只需要使用 'typeahead.input' 因为编译后它会查看自己的范围
    • 我刚刚做的其他事情是使用 scope.typeahead = scope.$eval(attrs.myTypeahead)。这样,人们既可以传递一个预先输入的实例,也可以传递一个最终会返回一个的函数。相当不错的技巧,虽然我仍然想知道我是否做错了什么(虽然它有效)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-14
    • 2016-07-07
    • 2018-02-15
    • 1970-01-01
    相关资源
    最近更新 更多