I want to create a directive that I can use on <select>
elements, to tell it to populate the <select>
with a globally known list that's dynamically updated and shared among all the components in the app.
我想创建一个可以在,该列表在应用程序的所有组件之间动态更新和共享。
I envision using it like so:
我想象着这样使用它:
<select ng-model="listentry" select-the-list></select>
Here's how I'm going about it so far:
到目前为止,我是这样做的:
.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);
}
};
});
That is, I assign an ng-options
attribute that does what I want, based on the scope that I set up for this purpose, and then $compile
it.
也就是说,我根据为此目的设置的范围分配一个ng-options属性,然后$compile它。
This works great. But note the line I commented with ATTENTION: This assumes that the user used <select select-the-list>
, which then got normalized to selectTheList
and used this directive. However, according to 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
).将元素的标记和属性名规范化,以确定哪些元素匹配哪些指令。我们通常通过区分大小写的camelCase规范化名称(例如ngModel)来引用指令。然而,由于HTML是不区分大小写的,所以我们使用小写形式来引用DOM中的指令,通常使用DOM元素(例如ng-model)的dash-delimited属性。
The normalization process is as follows: [... snip ...]
归一化过程如下:剪断…]
For example, the following forms are all equivalent and match the
ngBind
directive:例如,以下表单都是等价的,并且与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>
That is, if a user does <select select:the:list>
, then the directive will be applied, element.removeAttr('select-the-list')
will not work, and I'll get an infinite loop.
也就是说,如果用户执行
This may be an XY problem, which is why I provided all this context. But if this is a good way to do it - what's the best way to find the actual attribute on the element that caused my directive to be called, so I can remove it before re-compiling it?
这可能是一个XY问题,这就是我提供所有这些上下文的原因。但是,如果这是一种很好的方法,那么找到使我的指令被调用的元素的实际属性的最佳方法是什么呢?
2 个解决方案
#1
2
The creators of angular did indeed envision the need for this. The attributes
passed into your link
function is not just a map, but an instance of $compile.directive.Attributes
. It contains an $attr
property:
角的创造者确实预见到了这一点的需要。传递给链接函数的属性不仅仅是一个映射,而是$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.
一个DOM元素属性的映射到规范化名称。这需要将规范化名称反向查找到实际名称。
Thus, your ATTENTION line should be:
因此,你的注意线应该是:
el.removeAttr(attributes.$attr['selectTheList']);
#2
1
This is XY problem indeed, because the subject is avoiding recursive compilation.
这确实是XY问题,因为主题避免了递归编译。
There are some tricks to handle this.
有一些技巧可以解决这个问题。
One of them is to make use of the fact that the only place where DDO object is available as this
is compile
:
其中之一是利用DDO对象在编译时唯一可用的地方:
...
compile: function (element, attrs) {
attrs.$set(this.name, null);
// so the appearance of 'compile' won't require nesting link fn
return this.link;
},
link: ...
And changing directive's name or pasting its code won't cause inconsistencies.
并且改变指令的名称或粘贴它的代码不会引起不一致。
Another one is more generic and is particularly useful if removing an attribute isn't applicable for some reason or the directive isn't an attribute:
另一种是更通用的,如果出于某种原因移除属性不适用,或者该指令不是属性,则特别有用:
link: function (scope, element) {
...
if (element.data('$recursion')) {
element.data('$recursion', false);
} else {
element.data('$recursion', true);
$compile(element)(scope);
}
}
#1
2
The creators of angular did indeed envision the need for this. The attributes
passed into your link
function is not just a map, but an instance of $compile.directive.Attributes
. It contains an $attr
property:
角的创造者确实预见到了这一点的需要。传递给链接函数的属性不仅仅是一个映射,而是$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.
一个DOM元素属性的映射到规范化名称。这需要将规范化名称反向查找到实际名称。
Thus, your ATTENTION line should be:
因此,你的注意线应该是:
el.removeAttr(attributes.$attr['selectTheList']);
#2
1
This is XY problem indeed, because the subject is avoiding recursive compilation.
这确实是XY问题,因为主题避免了递归编译。
There are some tricks to handle this.
有一些技巧可以解决这个问题。
One of them is to make use of the fact that the only place where DDO object is available as this
is compile
:
其中之一是利用DDO对象在编译时唯一可用的地方:
...
compile: function (element, attrs) {
attrs.$set(this.name, null);
// so the appearance of 'compile' won't require nesting link fn
return this.link;
},
link: ...
And changing directive's name or pasting its code won't cause inconsistencies.
并且改变指令的名称或粘贴它的代码不会引起不一致。
Another one is more generic and is particularly useful if removing an attribute isn't applicable for some reason or the directive isn't an attribute:
另一种是更通用的,如果出于某种原因移除属性不适用,或者该指令不是属性,则特别有用:
link: function (scope, element) {
...
if (element.data('$recursion')) {
element.data('$recursion', false);
} else {
element.data('$recursion', true);
$compile(element)(scope);
}
}