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.
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
).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>
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?
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:
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.
Thus, your ATTENTION line should be:
el.removeAttr(attributes.$attr['selectTheList']);