如何在 normalized/denormalize 属性名称之前获取原始属性名称?
How to get the original attribute name before it was normalized/denormalize an attribute name?
我想创建一个我可以在 <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
它。
效果很好。但请注意我用 ATTENTION 评论的行:这假设用户使用 <select select-the-list>
,然后将其规范化为 selectTheList
并使用此指令。然而,根据 the directive docs:
Angular normalizes an element's tag and attribute name to determine which elements match which directives. We typically refer to directives by their case-sensitive camelCase normalized name (e.g. ngModel
). However, since HTML is case-insensitive, we refer to directives in the DOM by lower-case forms, typically using dash-delimited attributes on DOM elements (e.g. ng-model
).
The normalization process is as follows: [... snip ...]
For example, the following forms are all equivalent and match the ngBind
directive:
<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,这就是我提供所有这些上下文的原因。但如果这是一个很好的方法 - 在导致我的指令被调用的元素上找到实际属性的最佳方法是什么,这样我就可以在重新编译之前删除它?
angular 的创建者确实预见到了这一需求。传递给 link
函数的 attributes
不仅仅是一个映射,而是 $compile.directive.Attributes
的一个实例。它包含一个 $attr
属性:
Properties
$attr
A map of DOM element attribute names to the normalized name. This is needed to do reverse lookup from normalized name back to actual name.
因此,您的 ATTENTION 行应该是:
el.removeAttr(attributes.$attr['selectTheList']);
这确实是XY问题,因为题目是在避免递归编译。
有一些技巧可以解决这个问题。
其中之一是利用 DDO 对象作为 this
可用的唯一位置是 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);
}
}
我想创建一个我可以在 <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
它。
效果很好。但请注意我用 ATTENTION 评论的行:这假设用户使用 <select select-the-list>
,然后将其规范化为 selectTheList
并使用此指令。然而,根据 the directive docs:
Angular normalizes an element's tag and attribute name to determine which elements match which directives. We typically refer to directives by their case-sensitive camelCase normalized name (e.g.
ngModel
). However, since HTML is case-insensitive, we refer to directives in the DOM by lower-case forms, typically using dash-delimited attributes on DOM elements (e.g.ng-model
).The normalization process is as follows: [... snip ...]
For example, the following forms are all equivalent and match the
ngBind
directive:
<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,这就是我提供所有这些上下文的原因。但如果这是一个很好的方法 - 在导致我的指令被调用的元素上找到实际属性的最佳方法是什么,这样我就可以在重新编译之前删除它?
angular 的创建者确实预见到了这一需求。传递给 link
函数的 attributes
不仅仅是一个映射,而是 $compile.directive.Attributes
的一个实例。它包含一个 $attr
属性:
Properties
$attr
A map of DOM element attribute names to the normalized name. This is needed to do reverse lookup from normalized name back to actual name.
因此,您的 ATTENTION 行应该是:
el.removeAttr(attributes.$attr['selectTheList']);
这确实是XY问题,因为题目是在避免递归编译。
有一些技巧可以解决这个问题。
其中之一是利用 DDO 对象作为 this
可用的唯一位置是 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);
}
}