Допустимые имена директив
-
21-12-2019 - |
Вопрос
У меня очень специфическая проблема с директивой, начинающейся с определенных букв (t, u, v, w, y, z).Директива используется на select
элемент и следит за ngOptions
изменения.
Когда ngOptions
заполняется данными из Ajax-запроса, а имя директивы начинается с определенной буквы, напримерw, второй обратный вызов Watch срабатывает до того, как будут созданы параметры выбора.Если имя директивы начинается с другой буквы (a, k, m, n), второй обратный вызов отслеживания срабатывает после создания параметров.
Вот образец с несколькими директивами, начинающимися с разных букв.Откройте консоль, чтобы увидеть проблему.
<select w-foo ng-model="bar" ng-options="o.name for o in options"></select>
app.controller("test", function ($scope, $timeout) {
// Emulate ajaxed options
$timeout(function () {
$scope.options = [{
name: "aaa",
id: 1
}, {
name: "bbb",
id: 2
}, {
name: "ccc",
id: 3
}];
}, 500);
});
app.directive("wFoo", function () {
return {
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
scope.$watch(attrs.ngOptions.replace(/.*in /, ""), function () {
console.log("w-foo ngOptions changed", element.html());
});
}
};
});
В приведенном выше коде element.html()
будет содержать один пустой option
в первом обратном вызове просмотра (начальный дайджест), а также будет содержать один пустой option
во втором дайджесте (когда Ajax будет завершен).
Откуда такое поведение?
Решение
Здесь есть три механизма, которые объясняют такое поведение:
Наблюдателей казнят в тот же порядок что они зарегистрированы(посмотреть код
$watch
метод()).Функции постлинка выполняются в обратный порядок своего приоритета (см. документацию по
priority
свойство).Директивы с одинаковым приоритетом выполняются в неопределенном порядке.Приоритет по умолчанию
0
, поэтому все ваши пользовательские директивы имеют этот приоритет.Посколькуselect
директива, а также приоритет0
, порядок выполнения не определен.Как вы заметили, слово «неопределено» немного избыточно, и на самом деле порядок выполнения такой же. Алфавитный порядок (увидеть
$compile
код):директивы с именем в начале словаря имеют более высокий приоритет.Но, по моему скромному мнению, поскольку в документации об этом прямо не сказано, ты не можешь полагаться на такое поведение.
Подводя итог, приведем несколько вариантов использования.Каждая директива регистрирует наблюдателя.
Name | Priority | Watcher order
--------+------------+--------------
A | 100 | 3rd
B | 0 | 2nd
C | none (= 0) | 1st
Таким образом, исправить проблему просто:
- Если вы хотите выполнить наблюдатель ваших пользовательских директив после тот
select
один, просто дайте вашей директиве приоритет выше, чем0
. - Если вы хотите выполнить наблюдатель ваших пользовательских директив до тот
select
один, ну… поскольку отрицательный приоритет запрещен, вы не можете сделать это надежно.