En los casos en que tenga varias directivas sobre un único elemento DOM y donde el orden en el que se aplican sea importante, puede usar la priority
propiedad para ordenar su aplicación. Los números más altos se ejecutan primero. La prioridad predeterminada es 0 si no especifica una.
EDITAR : después de la discusión, aquí está la solución de trabajo completa. La clave era eliminar el atributo : element.removeAttr("common-things");
y también element.removeAttr("data-common-things");
(en caso de que los usuarios especifiquen data-common-things
en el 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);
}
};
}
};
});
El programa de trabajo está disponible en: http://plnkr.co/edit/Q13bUt?p=preview
O:
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);
}
};
});
MANIFESTACIÓN
Explicación de por qué tenemos que configurar terminal: true
y priority: 1000
(un número alto):
Cuando el DOM está listo, angular lo recorre para identificar todas las directivas registradas y compilar las directivas una por una en función de priority
si estas directivas están en el mismo elemento . Establecemos la prioridad de nuestra directiva personalizada en un número alto para asegurarnos de que se compile primero y con terminal: true
las otras directivas se omitirán después de que se compile esta directiva.
Cuando se compila nuestra directiva personalizada, modificará el elemento agregando directivas y eliminándose a sí mismo y usará el servicio $ compile para compilar todas las directivas (incluidas las que se omitieron) .
Si no configuramos terminal:true
y priority: 1000
, existe la posibilidad de que algunas directivas se compilen antes que nuestra directiva personalizada. Y cuando nuestra directiva personalizada usa $ compile para compilar el elemento => compila nuevamente las directivas ya compiladas. Esto provocará un comportamiento impredecible, especialmente si las directivas compiladas antes de nuestra directiva personalizada ya han transformado el DOM.
Para obtener más información sobre prioridad y terminal, consulte ¿Cómo entender el `terminal` de la directiva?
Un ejemplo de una directiva que también modifica la plantilla es ng-repeat
(prioridad = 1000), cuando ng-repeat
se compila, ng-repeat
haga copias del elemento de la plantilla antes de que se apliquen otras directivas .
Gracias al comentario de @ Izhaki, aquí está la referencia al ngRepeat
código fuente: https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js
RangeError: Maximum call stack size exceeded
medida que continúa compilando para siempre.element.removeAttr("common-datepicker");
para evitar bucles indefinidos.replace: false
,terminal: true
,priority: 1000
; luego establezca los atributos deseados en lacompile
función y elimine nuestro atributo de directiva. Finalmente, en lapost
función devuelta porcompile
, call$compile(element)(scope)
. El elemento se compilará regularmente sin la directiva personalizada pero con los atributos agregados. Lo que estaba tratando de lograr era no eliminar la directiva personalizada y manejar todo esto en un solo proceso: parece que esto no se puede hacer. Consulte el plnkr actualizado: plnkr.co/edit/Q13bUt?p=preview .common-things
atributos, puede pasar un parámetro maxPriority al comando de compilación:$compile(element, null, 1000)(scope);
En realidad, puede manejar todo esto con solo una simple etiqueta de plantilla. Consulte http://jsfiddle.net/m4ve9/ para ver un ejemplo. Tenga en cuenta que en realidad no necesitaba una propiedad de compilación o enlace en la definición de super-directiva.
Durante el proceso de compilación, Angular extrae los valores de la plantilla antes de la compilación, por lo que puede adjuntar cualquier directiva adicional allí y Angular se encargará de usted.
Si se trata de una súper directiva que necesita preservar el contenido interno original, puede usar
transclude : true
y reemplazar el interior con<ng-transclude></ng-transclude>
Espero que ayude, avíseme si algo no está claro
Alex
fuente
input
etiqueta, pero me gustaría que funcione para cualquier elemento, comodiv
s oselect
s.element
y pasarlaattrs
. Me llevó años resolverlo, y no lo he visto usado en ningún lado, pero parece funcionar bien: stackoverflow.com/a/20137542/1455709Aquí hay una solución que mueve las directivas que deben agregarse dinámicamente a la vista y también agrega lógica condicional (básica) opcional. Esto mantiene la directiva limpia sin lógica codificada.
La directiva toma una matriz de objetos, cada objeto contiene el nombre de la directiva que se agregará y el valor que se le pasará (si corresponde).
Estaba luchando por pensar en un caso de uso para una directiva como esta hasta que pensé que podría ser útil agregar alguna lógica condicional que solo agregue una directiva basada en alguna condición (aunque la respuesta a continuación todavía es artificial). Agregué una
if
propiedad opcional que debería contener un valor bool, expresión o función (por ejemplo, definida en su controlador) que determina si la directiva debe agregarse o no.También estoy usando
attrs.$attr.dynamicDirectives
para obtener la declaración de atributo exacta utilizada para agregar la directiva (por ejemplodata-dynamic-directive
,dynamic-directive
) sin codificar los valores de cadena para verificar.Plunker Demo
fuente
Quería agregar mi solución ya que la aceptada no funcionó para mí.
Necesitaba agregar una directiva pero también mantener la mía en el elemento.
En este ejemplo, estoy agregando una simple directiva ng-style al elemento. Para evitar bucles de compilación infinitos y permitirme mantener mi directiva, agregué un cheque para ver si lo que agregué estaba presente antes de volver a compilar el elemento.
fuente
Intente almacenar el estado en un atributo en el elemento en sí, como
superDirectiveStatus="true"
Por ejemplo:
Espero que esto te ayude.
fuente
Hubo un cambio de 1.3.x a 1.4.x.
En Angular 1.3.x esto funcionó:
Ahora en Angular 1.4.x tenemos que hacer esto:
(De la respuesta aceptada: https://stackoverflow.com/a/19228302/605586 de Khanh TO).
fuente
Una solución simple que podría funcionar en algunos casos es crear y $ compilar un contenedor y luego agregarle su elemento original.
Algo como...
Esta solución tiene la ventaja de que simplifica las cosas al no volver a compilar el elemento original.
Esto no funcionaría si alguna de las directivas agregadas es
require
alguna de las directivas del elemento original o si el elemento original tiene un posicionamiento absoluto.fuente