Dans les cas où vous avez plusieurs directives sur un seul élément DOM et où l'ordre dans lequel elles sont appliquées, vous pouvez utiliser la priority
propriété pour ordonner leur application. Les nombres plus élevés s'exécutent en premier. La priorité par défaut est 0 si vous n'en spécifiez pas.
EDIT : après la discussion, voici la solution de travail complète. La clé était de supprimer l'attribut :, element.removeAttr("common-things");
et aussi element.removeAttr("data-common-things");
(au cas où les utilisateurs le spécifieraient data-common-things
dans le html)
angular.module('app')
.directive('commonThings', function ($compile) {
return {
restrict: 'A',
replace: false,
terminal: true, //this setting is important, see explanation below
priority: 1000, //this setting is important, see explanation below
compile: function compile(element, attrs) {
element.attr('tooltip', '{{dt()}}');
element.attr('tooltip-placement', 'bottom');
element.removeAttr("common-things"); //remove the attribute to avoid indefinite loop
element.removeAttr("data-common-things"); //also remove the same attribute with data- prefix in case users specify data-common-things in the html
return {
pre: function preLink(scope, iElement, iAttrs, controller) { },
post: function postLink(scope, iElement, iAttrs, controller) {
$compile(iElement)(scope);
}
};
}
};
});
Plunker de travail est disponible à: http://plnkr.co/edit/Q13bUt?p=preview
Ou:
angular.module('app')
.directive('commonThings', function ($compile) {
return {
restrict: 'A',
replace: false,
terminal: true,
priority: 1000,
link: function link(scope,element, attrs) {
element.attr('tooltip', '{{dt()}}');
element.attr('tooltip-placement', 'bottom');
element.removeAttr("common-things"); //remove the attribute to avoid indefinite loop
element.removeAttr("data-common-things"); //also remove the same attribute with data- prefix in case users specify data-common-things in the html
$compile(element)(scope);
}
};
});
DEMO
Explication pourquoi nous devons définir terminal: true
et priority: 1000
(un nombre élevé):
Lorsque le DOM est prêt, angular parcourt le DOM pour identifier toutes les directives enregistrées et compiler les directives une par une en fonction de priority
si ces directives se trouvent sur le même élément . Nous avons défini la priorité de notre directive personnalisée sur un nombre élevé pour nous assurer qu'elle sera compilée en premier et avec terminal: true
, les autres directives seront ignorées après la compilation de cette directive.
Lorsque notre directive personnalisée est compilée, elle modifie l'élément en ajoutant et en supprimant elle-même et en utilisant le service $ compile pour compiler toutes les directives (y compris celles qui ont été ignorées) .
Si nous ne définissons pas terminal:true
et priority: 1000
, il est possible que certaines directives soient compilées avant notre directive personnalisée. Et lorsque notre directive personnalisée utilise $ compile pour compiler l'élément => recompiler à nouveau les directives déjà compilées. Cela entraînera un comportement imprévisible, surtout si les directives compilées avant notre directive personnalisée ont déjà transformé le DOM.
Pour plus d'informations sur la priorité et le terminal, consultez Comment comprendre le `terminal` de la directive?
Un exemple de directive qui modifie également le modèle est ng-repeat
(priorité = 1000), quand il ng-repeat
est compilé, ng-repeat
faites des copies de l'élément de modèle avant que d'autres directives ne soient appliquées .
Merci au commentaire de @ Izhaki, voici la référence au ngRepeat
code source: https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js
RangeError: Maximum call stack size exceeded
fur et à mesure de sa compilation.element.removeAttr("common-datepicker");
pour éviter la boucle indéfinie.replace: false
,terminal: true
,priority: 1000
; puis définissez les attributs souhaités dans lacompile
fonction et supprimez notre attribut directive. Enfin, dans lapost
fonction retournée parcompile
, appelez$compile(element)(scope)
. L'élément sera régulièrement compilé sans la directive personnalisée mais avec les attributs ajoutés. Ce que j'essayais de réaliser n'était pas de supprimer la directive personnalisée et de gérer tout cela en un seul processus: cela ne peut pas être fait, semble-t-il. Veuillez vous référer au plnkr mis à jour: plnkr.co/edit/Q13bUt?p=preview .common-things
attributs, vous pouvez passer un paramètre maxPriority à la commande de compilation:$compile(element, null, 1000)(scope);
Vous pouvez réellement gérer tout cela avec une simple balise de modèle. Voir http://jsfiddle.net/m4ve9/ pour un exemple. Notez que je n'avais en fait pas besoin d'une propriété de compilation ou de lien sur la définition de super-directive.
Pendant le processus de compilation, Angular extrait les valeurs du modèle avant la compilation, vous pouvez donc y attacher d'autres directives et Angular s'en chargera pour vous.
S'il s'agit d'une super directive qui doit conserver le contenu interne d'origine, vous pouvez utiliser
transclude : true
et remplacer l'intérieur par<ng-transclude></ng-transclude>
J'espère que cela aide, faites-moi savoir si quelque chose n'est pas clair
Alex
la source
input
balise, mais j'aimerais le faire fonctionner pour n'importe quel élément, commediv
s ouselect
s.element
etattrs
transmis. Cela m'a pris beaucoup de temps pour le résoudre , et je ne l'ai vu utilisé nulle part - mais il semble fonctionner correctementVoici une solution qui déplace les directives qui doivent être ajoutées dynamiquement dans la vue et ajoute également une logique conditionnelle facultative (de base). Cela permet de garder la directive propre sans logique codée en dur.
La directive prend un tableau d'objets, chaque objet contient le nom de la directive à ajouter et la valeur à lui transmettre (le cas échéant).
J'avais du mal à penser à un cas d'utilisation pour une directive comme celle-ci jusqu'à ce que je pense qu'il pourrait être utile d'ajouter une logique conditionnelle qui n'ajoute qu'une directive basée sur une condition (bien que la réponse ci-dessous soit toujours artificielle). J'ai ajouté une option
if
propriété qui devrait contenir une valeur booléenne, une expression ou une fonction (par exemple définie dans votre contrôleur) qui détermine si la directive doit être ajoutée ou non.J'utilise également
attrs.$attr.dynamicDirectives
pour obtenir la déclaration d'attribut exacte utilisée pour ajouter la directive (par exempledata-dynamic-directive
,dynamic-directive
) sans valeurs de chaîne codées en dur à vérifier.Plunker Demo
la source
Je voulais ajouter ma solution car celle acceptée ne fonctionnait pas tout à fait pour moi.
J'avais besoin d'ajouter une directive mais aussi de garder la mienne sur l'élément.
Dans cet exemple, j'ajoute une simple directive de style ng à l'élément. Pour éviter les boucles de compilation infinies et me permettre de conserver ma directive, j'ai ajouté une vérification pour voir si ce que j'avais ajouté était présent avant de recompiler l'élément.
la source
Essayez de stocker l'état dans un attribut sur l'élément lui-même, tel que
superDirectiveStatus="true"
Par exemple:
J'espère que ceci vous aide.
la source
Il y a eu un changement de 1.3.x à 1.4.x.
Dans Angular 1.3.x, cela fonctionnait:
Maintenant, dans Angular 1.4.x, nous devons le faire:
(D'après la réponse acceptée: https://stackoverflow.com/a/19228302/605586 de Khanh TO).
la source
Une solution simple qui pourrait fonctionner dans certains cas est de créer et de compiler $ un wrapper, puis d'y ajouter votre élément d'origine.
Quelque chose comme...
Cette solution a l'avantage de simplifier les choses en ne recompilant pas l'élément d'origine.
Cela ne fonctionnerait pas si l'une des directives de l'
require
une des directives de l'élément ajouté ou si l'élément d'origine avait un positionnement absolu.la source