我想创建一个可以在<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,这就是我提供所有这些背景的原因。但是如果这是一个很好的方法 - 找到导致我的指令被调用的元素的实际属性的最佳方法是什么,所以我可以在重新编译它之前删除它?
答案 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);
}
}