Noms de directives valides
-
21-12-2019 - |
Question
J'ai un problème très spécifique avec une directive commençant par certaines lettres (t, u, v, w, y, z).La directive est utilisée sur un select
élément et surveille ngOptions
changements.
Quand ngOptions
est rempli avec les données d'une requête Ajax et le nom de la directive commence par une certaine lettre, par ex.w, le deuxième rappel de surveillance se déclenche avant que les options de sélection n'aient été créées.Si le nom de la directive commence par une lettre différente (a, k, m, n), le deuxième rappel de surveillance se déclenche une fois les options créées.
Voici un échantillon avec plusieurs directives commençant par différentes lettres.Ouvrez votre console pour voir le problème.
<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());
});
}
};
});
Dans le code ci-dessus, element.html()
contiendra un seul vide option
dans le premier rappel de surveillance (le résumé initial) et contiendra également un seul vide option
dans le deuxième résumé (lorsque l'Ajax est terminé).
D'où vient ce comportement ?
La solution
Il y a ici trois mécanismes qui sont impliqués pour expliquer ce comportement :
Les observateurs sont exécutés dans le même ordre qu'ils sont enregistrés (voir le code du
$watch
méthode()).Les fonctions post-lien sont exécutées dans le ordre inverse de leur priorité (voir la documentation du
priority
propriété).Les directives avec la même priorité sont exécutées dans un ordre indéfini.La priorité par défaut est
0
, donc toutes vos directives personnalisées ici ont cette priorité.Depuis leselect
directive comme également une priorité de0
, l'ordre d'exécution n'est pas défini.Comme vous le remarquez, "undefined" est un peu excessif, et en réalité l'ordre d'exécution est le ordre alphabétique (voir le
$compile
code) :les directives avec un nom au début du dictionnaire ont une priorité plus élevée.Mais, à mon humble avis, puisque cela n'est pas explicitement dit dans la documentation, tu ne peux pas compter sur ce comportement.
Pour résumer, voici quelques cas d'utilisation.Chaque directive enregistre un observateur.
Name | Priority | Watcher order
--------+------------+--------------
A | 100 | 3rd
B | 0 | 2nd
C | none (= 0) | 1st
Ainsi, pour résoudre le problème, c'est simple :
- Si vous souhaitez exécuter le watcher de vos directives personnalisées après le
select
un, donnez simplement à votre directive une priorité supérieure à0
. - Si vous souhaitez exécuter le watcher de vos directives personnalisées avant le
select
un, eh bien… puisque les priorités négatives sont interdites, vous ne pouvez pas le faire de manière fiable.