Ajouter les directives de la directive en AngularJS
Je suis en train de construire une directive qui prend soin de l'ajout de plus de directives de l'élément, il est déclaré sur.
Par exemple, je veux construire une directive qui prend soin d'ajouter datepicker
, datepicker-language
et ng-required="true"
.
Si j'essaie d'ajouter des attributs et ensuite utiliser $compile
j'ai évidemment générer une boucle infinie, donc je vérifie si j'ai déjà ajouté les attributs requis:
angular.module('app')
.directive('superDirective', function ($compile, $injector) {
return {
restrict: 'A',
replace: true,
link: function compile(scope, element, attrs) {
if (element.attr('datepicker')) { //check
return;
}
element.attr('datepicker', 'someValue');
element.attr('datepicker-language', 'en');
//some more
$compile(element)(scope);
}
};
});
Bien sûr, si je n'ai pas $compile
les éléments, les attributs seront ensemble, mais la directive ne sera pas démarré.
Cette approche est-elle correcte ou suis-je tout faux? Est-il un meilleur moyen d'atteindre le même comportement?
UDPATE: compte tenu du fait que $compile
est la seule façon d'atteindre cet objectif, il est un moyen de sauter la première compilation pass (l'élément peut contenir plusieurs enfants)? Peut-être par la mise en terminal:true
?
Mise à JOUR 2: j'ai essayé de mettre la directive en un select
élément et, comme prévu, la compilation se déroule deux fois, ce qui signifie qu'il est deux fois le nombre de option
s.
Vous devez vous connecter pour publier un commentaire.
Dans le cas où vous avez plusieurs directives sur un seul élément du DOM et où l'
l'ordre dans lequel ils sont appliqués des questions, vous pouvez utiliser le
priority
propriété à l'ordre de leurapplication. Les numéros les plus élevés exécuter en premier. La priorité par défaut est 0 si vous ne spécifiez pas un.
MODIFIER: après la discussion, voici la complète solution de travail. La clé était de supprimer l'attribut:
element.removeAttr("common-things");
, et aussielement.removeAttr("data-common-things");
(dans le cas des utilisateurs de spécifierdata-common-things
dans le code html)De travail plunker est disponible à: http://plnkr.co/edit/Q13bUt?p=preview
Ou:
DÉMO
Explication des raisons pour lesquelles nous avons à mettre en
terminal: true
etpriority: 1000
(un grand nombre):Lorsque le DOM est prêt, angulaire marche dans les DOM pour identifier tous les inscrits de directives et de compiler les directives basée sur
priority
si ces directives sont sur le même élément. Nous avons mis notre coutume de la directive en priorité à un nombre élevé afin de s'assurer qu'il sera compilé première et avecterminal: true
, les autres directives seront sauté après cette directive est compilé.Lors de notre coutume directive est compilé, il va modifier l'élément par l'ajout de directives et de suppression de lui-même et d'utiliser $compiler service à compiler toutes les directives (y compris ceux qui ont été ignorés).
Si nous ne fixons pas les
terminal:true
etpriority: 1000
, il ya une chance que certaines directives sont compilés avant notre coutume directive. Et quand notre coutume directive utilise $compiler compiler l'élément => compiler à nouveau la déjà établi des directives. Cela va provoquer un comportement imprévisible, surtout si les directives compilé avant notre coutume directive ont déjà transformé les DOM.Pour plus d'informations à propos de la priorité et de terminal, découvrez Comment comprendre le "terminal" de la directive?
Un exemple d'une directive qui modifie également le modèle est
ng-repeat
(priorité = 1000), lorsqueng-repeat
est compilé,ng-repeat
faire des copies de l'élément de modèle, avant que d'autres directives appliquées.Grâce à @Izhaki commentaire, voici la référence à
ngRepeat
code source: https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.jsRangeError: Maximum call stack size exceeded
comme il va sur la compilation forever.element.removeAttr("common-datepicker");
pour éviter la boucle indéterminée.tooltip
. Letooltip
est indiqué, mais leselect
options sont définies deux fois. La première combine l'élément sans les nouveaux attributs, et ajoute l'sélectionnez options. La deuxième combine l'élément avec les attributs ajoutés récemment, mais ajoute de ces options.replace: false
,terminal: true
,priority: 1000
; puis définissez les attributs dans lecompile
fonction et enlever nos directive attribut. Enfin, dans lepost
fonction renvoyée parcompile
, appel$compile(element)(scope)
. L'élément sera régulièrement compilé sans la coutume directive, mais avec les attributs ajoutés. Ce que j'essayais de faire, c'est de ne pas supprimer la personnalisation de la directive et de gérer tout cela en un seul processus: cela ne peut pas être fait, il me semble. Veuillez vous référer à la mise à jour plnkr: plnkr.co/modifier/Q13bUt?p=preview.data-common-things
? Je m'attends à le voirelement.removeAttr("data-common-things");
dans lecompile
ainsi.require: 'ngModel'
il échoue...require: 'ngModel'
.require: "abc"
. L'accès parent contrôleurs est très bien, par exemple,require: '^def'
mais frère contrôleurs semblent hors de question?ng-model
et il est ramassé?common-things
les attributs, vous pouvez passer une maxPriority paramètre à la commande de la compilation:$compile(element, null, 1000)(scope);
ng-repeat
a une priorité de 1000, mettre un plus grand nombre si vous avez besoin de courir avant.Vous pouvez réellement gérer tout cela avec une simple balise de modèle. Voir http://jsfiddle.net/m4ve9/ pour un exemple. Notez qu'en fait je n'ai pas besoin d'une compilation ou d'un lien de propriété sur le super-directive définition.
Pendant le processus de compilation, Angulaire tire dans les valeurs de modèle avant de compiler, de sorte que vous pouvez joindre tout autres directives là et Angulaire prendra soin de cela pour vous.
Si c'est un super directive qui doit conserver l'original de contenu interne, vous pouvez utiliser
transclude : true
et remplacer l'intérieur avec<ng-transclude></ng-transclude>
Espère que ça aide, laissez-moi savoir si quelque chose n'est pas clair
Alex
input
tag, mais j'aimerais le faire fonctionner pour n'importe quel élément, commediv
s ouselect
s.element
etattrs
passé. M'a pris âge de travailler, et je n'ai pas vu utilisé n'importe où - mais il semble bien fonctionner: stackoverflow.com/a/20137542/1455709Voici une solution qui déplace les directives qui doivent être ajoutés de façon dynamique, dans le point de vue et ajoute également une option (de base), à la condition logique. Ce qui maintient la directive propre, sans codée en dur de la logique.
La directive prend un tableau d'objets, chaque objet contient le nom de la directive, l'ajout de la valeur à transmettre à celle-ci (le cas échéant).
J'avais du mal à penser à un cas d'utilisation pour une directive comme cela jusqu'à ce que j'ai pensé qu'il pourrait être utile d'ajouter de la logique conditionnelle qui n'ajoute qu'une directive basée sur une condition (si la réponse ci-dessous est toujours fictive). J'ai ajouté une option de
if
propriété que doit contenir une valeur booléenne, de l'expression ou de la fonction (par exemple défini dans votre controller) qui détermine si la directive doit être ajouté ou non.Je suis également en utilisant
attrs.$attr.dynamicDirectives
d'obtenir la déclaration d'attribut utilisé pour ajouter de la directive (par exemple,data-dynamic-directive
,dynamic-directive
) sans coder en dur les valeurs de chaîne à vérifier.Plunker Démo
JS:
HTML:
Je voulais ajouter ma solution depuis le accepté l'on n'a pas assez de travail pour moi.
J'ai besoin d'ajouter une directive, mais aussi garder la mienne sur l'élément.
Dans cet exemple, je suis l'ajout d'une simple ng-style de la directive de l'élément. Pour empêcher l'infini de la compilation de boucles et de me permettre de garder mon directive j'ai ajouté une vérification pour voir si ce que j'ai ajouté était présent avant de recompiler l'élément.
Essayez de stocker l'état dans un attribut de l'élément lui-même, comme
superDirectiveStatus="true"
Par exemple:
J'espère que cela vous aide.
Il y avait un changement de 1.3.x 1.4.x.
Angulaire 1.3.x cela a fonctionné:
Maintenant Angulaire 1.4.x nous avons pour ce faire:
(À partir de la accepté de répondre: https://stackoverflow.com/a/19228302/605586 de Khanh POUR).
Une solution simple qui peut, dans certains cas, est de créer et de $compiler un wrapper puis ajouter l'original de votre élément.
Quelque chose comme...
Cette solution a l'avantage qu'il garde les choses simples, pas la recompilation de l'élément d'origine.
Ceci ne fonctionnerait pas si tout de la valeur ajoutée de la directive
require
un de l'original de l'élément de directives ou si l'élément d'origine a un positionnement absolu.