如何在规范化/非规范化属性名称之前获取原始属性名称?

时间:2015-11-12 00:28:44

标签: javascript angularjs angularjs-directive angularjs-compile

我想创建一个可以在<select>元素上使用的指令,告诉它使用全局已知的列表填充<select>,该列表在应用程序的所有组件之间动态更新和共享。

我设想像这样使用它:

<select ng-model="listentry" select-the-list></select>

到目前为止,我的目标是:

.directive('selectTheList', function ($compile, ListData) {
    return {
        restrict: 'A',
        priority: 1000,
        terminal: true,
        link: function (scope, el, attributes) {
            var child = scope.$new();
            child.listData = ListData.theList;
            el.attr('ng-options', 'listItem.name for listItem in listData track by listItem.id');
            el.removeAttr('select-the-list'); /**** ATTENTION ****/
            $compile(el)(child);
        }
    };
});

也就是说,我根据我为此目的设置的范围,然后ng-options分配$compile属性来执行我想要的操作。

这很有效。但请注意我用注意评论的行:这假设用户使用<select select-the-list>,然后将其标准化为selectTheList并使用此指令。但是,根据the directive docs

  

Angular 规范化元素的标记和属性名称,以确定哪些元素与哪些指令匹配。我们通常通过区分大小写的camelCase 规范化名称(例如ngModel)来引用指令。但是,由于HTML不区分大小写,我们通过小写形式引用DOM中的指令,通常在DOM元素上使用dash-delimited属性(例如ng-model)。

     

规范化过程如下:[... snip ...]

     

例如,以下表单都是等效的,并且与ngBind指令匹配:

<div ng-controller="Controller">
  Hello <input ng-model='name'> <hr/>
  <span ng-bind="name"></span> <br/>
  <span ng:bind="name"></span> <br/>
  <span ng_bind="name"></span> <br/>
  <span data-ng-bind="name"></span> <br/>
  <span x-ng-bind="name"></span> <br/>
</div>

也就是说,如果用户执行<select select:the:list>,则会应用该指令,element.removeAttr('select-the-list')将无效,我将获得无限循环

这可能是XY problem,这就是我提供所有这些背景的原因。但是如果这是一个很好的方法 - 找到导致我的指令被调用的元素的实际属性的最佳方法是什么,所以我可以在重新编译它之前删除它?

2 个答案:

答案 0 :(得分:2)

角度的创造者确实设想了对此的需求。传递到attributes函数的link不仅仅是地图,还有$compile.directive.Attributes的实例。它包含$attr属性:

  

属性

     

$ ATTR

     

DOM元素属性名称到规范化名称的映射。这需要从规范化名称反向查找到实际名称。

因此,您的注意行应为:

el.removeAttr(attributes.$attr['selectTheList']);

答案 1 :(得分:1)

这确实是XY问题,因为主题是避免递归编译。

有一些技巧可以解决这个问题。

其中一个是利用这样一个事实:this唯一可以使用DDO对象的地方是compile

...
compile: function (element, attrs)  {
  attrs.$set(this.name, null);
  // so the appearance of 'compile' won't require nesting link fn
  return this.link;
},
link: ...

更改指令的名称或粘贴其代码不会导致不一致。

另一个更通用,如果由于某种原因删除属性不适用或指令不是属性,则特别有用:

link: function (scope, element) {
    ...
    if (element.data('$recursion')) {
        element.data('$recursion', false);
    } else {
        element.data('$recursion', true);
        $compile(element)(scope);
    }
}