Как получить оригинальное имя атрибута до его нормализации / денормализации имени атрибута?
Я хочу создать директиву, которую я могу использовать на <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
и использовал эту директиву. Тем не менее, в соответствии с директивой документов:
Angular нормализует тег элемента и имя атрибута, чтобы определить, какие элементы соответствуют каким директивам. Обычно мы ссылаемся на директивы по их чувствительному к регистру нормализованному имени camelCase (например,
ngModel
). Однако, поскольку HTML не чувствителен к регистру, мы обращаемся к директивам в DOM с помощью строчных форм, обычно используя атрибуты с разделителями-тире в элементах DOM (например,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, поэтому я предоставил весь этот контекст. Но если это хороший способ сделать это - как лучше всего найти фактический атрибут в элементе, который вызвал мою директиву, чтобы я мог удалить его перед повторной компиляцией?
2 ответа
Создатели angular действительно предполагали необходимость в этом. attributes
перешел в ваш link
Функция не просто карта, но экземпляр $compile.directive.Attributes
, Содержит $attr
имущество:
свойства
$ атр
Карта имен атрибутов элемента DOM к нормализованному имени. Это необходимо для обратного поиска от нормализованного имени до фактического имени.
Таким образом, ваша строка ВНИМАНИЕ должна быть:
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);
}
}