angularjs - crear - Directivas angulares: cuándo y cómo usar compilación, controlador, enlace previo y enlace posterior
link angularjs directive (8)
Al escribir una directiva angular, se puede usar cualquiera de las siguientes funciones para manipular el comportamiento, el contenido y el aspecto del DOM en el que se declara la directiva:
- compilar
- controlador
- enlace previo
- enlace posterior
Parece que hay cierta confusión en cuanto a qué función se debe usar. Esta pregunta cubre:
Fundamentos de la directiva
- ¿Cómo declarar las diversas funciones?
- ¿Cuál es la diferencia entre una plantilla de origen y una plantilla de instancia ?
- ¿En qué orden se ejecutan las funciones directivas?
- ¿Qué más sucede entre estas llamadas de función?
Naturaleza de la función, hacer y no hacer.
- Compile
- Controller
- Pre-link
- Post-link
Preguntas relacionadas:
- Directiva: enlace vs compilar vs controlador .
- Diferencia entre las funciones ''controlador'', ''enlace'' y ''compilar'' al definir una directiva angular.js .
- ¿Cuál es la diferencia entre la función de compilación y enlace en angularjs .
- ¿Diferencia entre el elemento de precompilación y posterior a la compilación en las directivas AngularJS? .
- Directiva JS Angular - ¿Plantilla, compilación o enlace? .
- Post link vs pre link en directivas angulares js .
¿Cómo declarar las diversas funciones?
Compilar, Controlador, Pre-link y Post-link
Si una es usar las cuatro funciones, la directiva seguirá este formulario:
myApp.directive( ''myDirective'', function () {
return {
restrict: ''EA'',
controller: function( $scope, $element, $attrs, $transclude ) {
// Controller code goes here.
},
compile: function compile( tElement, tAttributes, transcludeFn ) {
// Compile code goes here.
return {
pre: function preLink( scope, element, attributes, controller, transcludeFn ) {
// Pre-link code goes here
},
post: function postLink( scope, element, attributes, controller, transcludeFn ) {
// Post-link code goes here
}
};
}
};
});
Tenga en cuenta que compile devuelve un objeto que contiene las funciones de enlace previo y posterior al enlace; en Angular lingo decimos que la función de compilación devuelve una función de plantilla .
Compilar, Controlador y Post-link
Si pre-link
no es necesario, la función de compilación puede simplemente devolver la función de enlace posterior en lugar de un objeto de definición, de este modo:
myApp.directive( ''myDirective'', function () {
return {
restrict: ''EA'',
controller: function( $scope, $element, $attrs, $transclude ) {
// Controller code goes here.
},
compile: function compile( tElement, tAttributes, transcludeFn ) {
// Compile code goes here.
return function postLink( scope, element, attributes, controller, transcludeFn ) {
// Post-link code goes here
};
}
};
});
A veces, uno desea agregar un método de compile
, después de que se definió el método de (publicación) link
. Para esto, uno puede usar:
myApp.directive( ''myDirective'', function () {
return {
restrict: ''EA'',
controller: function( $scope, $element, $attrs, $transclude ) {
// Controller code goes here.
},
compile: function compile( tElement, tAttributes, transcludeFn ) {
// Compile code goes here.
return this.link;
},
link: function( scope, element, attributes, controller, transcludeFn ) {
// Post-link code goes here
}
};
});
Controlador y enlace posterior
Si no se necesita una función de compilación, se puede omitir su declaración por completo y proporcionar la función de enlace posterior bajo la propiedad de link
del objeto de configuración de la directiva:
myApp.directive( ''myDirective'', function () {
return {
restrict: ''EA'',
controller: function( $scope, $element, $attrs, $transclude ) {
// Controller code goes here.
},
link: function postLink( scope, element, attributes, controller, transcludeFn ) {
// Post-link code goes here
},
};
});
Sin controlador
En cualquiera de los ejemplos anteriores, uno puede simplemente eliminar la función del controller
si no es necesario. Entonces, por ejemplo, si solo se necesita la función de post-link
, se puede usar:
myApp.directive( ''myDirective'', function () {
return {
restrict: ''EA'',
link: function postLink( scope, element, attributes, controller, transcludeFn ) {
// Post-link code goes here
},
};
});
¿Cuál es la diferencia entre una plantilla de origen y una plantilla de instancia ?
El hecho de que Angular permita la manipulación de DOM significa que el marcado de entrada en el proceso de compilación a veces difiere de la salida. En particular, algunas marcas de entrada pueden clonarse unas cuantas veces (como con ng-repeat
) antes de procesarse en el DOM.
La terminología angular es un poco inconsistente, pero aún distingue dos tipos de marcas:
- Plantilla de origen : el marcado que se va a clonar, si es necesario. Si se clona, este marcado no se representará en el DOM.
- Plantilla de instancia : el marcado real que se representará en el DOM. Si se trata de una clonación, cada instancia será un clon.
El siguiente marcado demuestra esto:
<div ng-repeat="i in [0,1,2]">
<my-directive>{{i}}</my-directive>
</div>
La fuente html define
<my-directive>{{i}}</my-directive>
que sirve como la plantilla de origen.
Pero como está dentro de una directiva ng-repeat
, esta plantilla de origen se clonará (3 veces en nuestro caso). Estos clones son una plantilla de instancia, cada uno aparecerá en el DOM y estará vinculado al ámbito relevante.
¿En qué orden se ejecutan las funciones directivas?
Para una sola directiva
Basado en el siguiente plunk , considere el siguiente marcado HTML:
<body>
<div log=''some-div''></div>
</body>
Con la siguiente declaración directiva:
myApp.directive(''log'', function() {
return {
controller: function( $scope, $element, $attrs, $transclude ) {
console.log( $attrs.log + '' (controller)'' );
},
compile: function compile( tElement, tAttributes ) {
console.log( tAttributes.log + '' (compile)'' );
return {
pre: function preLink( scope, element, attributes ) {
console.log( attributes.log + '' (pre-link)'' );
},
post: function postLink( scope, element, attributes ) {
console.log( attributes.log + '' (post-link)'' );
}
};
}
};
});
La salida de la consola será:
some-div (compile)
some-div (controller)
some-div (pre-link)
some-div (post-link)
Podemos ver que la compile
se ejecuta primero, luego el controller
, luego pre-link
y el último es post-link
.
Para directivas anidadas.
Nota: lo siguiente no se aplica a las directivas que representan a sus hijos en su función de enlace. Muchas directivas angulares lo hacen (como ngIf, ngRepeat o cualquier directiva con
transclude
). Estas directivas tendrán su función delink
forma nativa antes de que se llame lacompile
directivas secundarias.
El marcado HTML original a menudo está hecho de elementos anidados, cada uno con su propia directiva. Como en el siguiente marcado (ver plunk ):
<body>
<div log=''parent''>
<div log=''..first-child''></div>
<div log=''..second-child''></div>
</div>
</body>
La salida de la consola se verá así:
// The compile phase
parent (compile)
..first-child (compile)
..second-child (compile)
// The link phase
parent (controller)
parent (pre-link)
..first-child (controller)
..first-child (pre-link)
..first-child (post-link)
..second-child (controller)
..second-child (pre-link)
..second-child (post-link)
parent (post-link)
Aquí podemos distinguir dos fases: la fase de compilación y la fase de enlace .
La fase de compilación
Cuando se carga el DOM, Angular inicia la fase de compilación, donde atraviesa el marcado de arriba hacia abajo y llama a compile
en todas las directivas. Gráficamente, podríamos expresarlo así:
Quizás sea importante mencionar que en esta etapa, las plantillas que obtiene la función de compilación son las plantillas de origen (no la plantilla de instancia).
La fase de enlace
Las instancias de DOM a menudo son simplemente el resultado de una plantilla de origen que se procesa en el DOM, pero pueden crearse mediante ng-repeat
o introducirse sobre la marcha.
Cada vez que una nueva instancia de un elemento con una directiva se representa en el DOM, se inicia la fase de enlace.
En esta fase, Angular llama al controller
, pre-link
, itera a los niños, y llama al post-link
en todas las directivas, así:
¿Qué más sucede entre estas llamadas de función?
Las diversas funciones de la directiva se ejecutan desde otras dos funciones angulares llamadas $compile
(donde se ejecuta la compile
la directiva) y una función interna llamada nodeLinkFn
(donde se ejecutan el controller
la directiva, preLink
y postLink
). Varias cosas suceden dentro de la función angular antes y después de que se llaman las funciones directivas. Quizás lo más notable es la recursión infantil. La siguiente ilustración simplificada muestra los pasos clave dentro de las fases de compilación y enlace:
Para demostrar estos pasos, usemos el siguiente código HTML:
<div ng-repeat="i in [0,1,2]">
<my-element>
<div>Inner content</div>
</my-element>
</div>
Con la siguiente directiva:
myApp.directive( ''myElement'', function() {
return {
restrict: ''EA'',
transclude: true,
template: ''<div>{{label}}<div ng-transclude></div></div>''
}
});
Compilar
La API de compile
ve así:
compile: function compile( tElement, tAttributes ) { ... }
A menudo, los parámetros tienen el prefijo t
para indicar que los elementos y los atributos proporcionados son los de la plantilla de origen, en lugar de los de la instancia.
Antes de la llamada para compile
contenido transcluido (si existe) se elimina, y la plantilla se aplica a la marca. Por lo tanto, el elemento proporcionado a la función de compile
se verá así:
<my-element>
<div>
"{{label}}"
<div ng-transclude></div>
</div>
</my-element>
Observe que el contenido transcluido no se reinserta en este punto.
Tras la llamada a la .compile
la directiva, Angular atravesará todos los elementos secundarios, incluidos aquellos que pueden haber sido introducidos por la directiva (los elementos de la plantilla, por ejemplo).
Creación de instancias
En nuestro caso, se crearán tres instancias de la plantilla de origen anterior (por ng-repeat
). Por lo tanto, la siguiente secuencia se ejecutará tres veces, una por instancia.
Controlador
La API del controller
implica:
controller: function( $scope, $element, $attrs, $transclude ) { ... }
Al ingresar a la fase de enlace, la función de enlace devuelta a través de $compile
ahora cuenta con un alcance.
Primero, la función de enlace crea un alcance secundario ( scope: true
) o un alcance aislado ( scope: {...}
) si se solicita.
Luego se ejecuta el controlador, provisto con el alcance del elemento de instancia.
Pre-enlace
La API de pre-link
ve así:
function preLink( scope, element, attributes, controller ) { ... }
Prácticamente no pasa nada entre la llamada al .controller
la directiva y la función .preLink
. Angular todavía proporciona recomendaciones sobre cómo se debe utilizar cada uno.
Después de la llamada .preLink
, la función de enlace atravesará cada elemento .preLink
llamará a la función de enlace correcta y adjuntará el alcance actual (que sirve como el ámbito principal para los elementos secundarios).
Enlace posterior
La API post-link
es similar a la de la función de pre-link
:
function postLink( scope, element, attributes, controller ) { ... }
Tal vez valga la pena notar que una vez que se llama la función .postLink
una directiva, el proceso de enlace de todos sus elementos .postLink
ha completado, incluidas todas las funciones .postLink
los niños.
Esto significa que cuando se llama a .postLink
, los niños están ''en vivo'' y están listos. Esto incluye:
- el enlace de datos
- transclusión aplicada
- alcance adjunto
La plantilla en esta etapa se verá así:
<my-element>
<div class="ng-binding">
"{{label}}"
<div ng-transclude>
<div class="ng-scope">Inner content</div>
</div>
</div>
</my-element>
Función de compilación
La función de compile
cada directiva solo se llama una vez, cuando Angular bootstraps.
Oficialmente, este es el lugar para realizar manipulaciones de plantillas (de origen) que no implican alcance o enlace de datos.
Principalmente, esto se hace con fines de optimización; Considere el siguiente marcado:
<tr ng-repeat="raw in raws">
<my-raw></my-raw>
</tr>
La directiva <my-raw>
representará un conjunto particular de marcado DOM. Entonces podemos:
- Permita que
ng-repeat
duplique la plantilla de origen (<my-raw>
) y luego modifique el marcado de cada plantilla de instancia (fuera de la función decompile
). - Modifique la plantilla de origen para incluir el marcado deseado (en la función de
compile
) y luego permita queng-repeat
duplique.
Si hay 1000 elementos en la colección de raws
, la última opción puede ser más rápida que la anterior.
Hacer:
- Manipular el marcado para que sirva de plantilla a instancias (clones).
No haga
- Adjuntar controladores de eventos.
- Inspeccionar elementos secundarios.
- Establecer observaciones sobre los atributos.
- Configurar relojes en el ámbito de aplicación.
Función de controlador
La función de controller
cada directiva se llama cada vez que se crea una instancia de un nuevo elemento relacionado.
Oficialmente, la función del controller
es donde uno:
- Define la lógica del controlador (métodos) que se pueden compartir entre los controladores.
- Inicia variables de alcance.
Nuevamente, es importante recordar que si la directiva involucra un alcance aislado, las propiedades dentro de él que heredan del alcance principal aún no están disponibles.
Hacer:
- Definir la lógica del controlador.
- Iniciar variables de alcance
No haga:
- Inspeccione elementos secundarios (es posible que aún no se hayan procesado, estén vinculados al alcance, etc.).
Función de enlace posterior
Cuando se llama a la función de post-link
, se han llevado a cabo todos los pasos anteriores: enlace, transclusión, etc.
Este suele ser un lugar para manipular aún más el DOM renderizado.
Hacer:
- Manipular elementos DOM (renderizados, y por lo tanto instanciados).
- Adjuntar controladores de eventos.
- Inspeccionar elementos secundarios.
- Establecer observaciones sobre los atributos.
- Configurar relojes en el ámbito de aplicación.
Función de pre-enlace
La función de pre-link
cada directiva se llama cada vez que se crea una instancia de un nuevo elemento relacionado.
Como se vio anteriormente en la sección de orden de compilación, pre-link
funciones de pre-link
se denominan padre-luego-hijo, mientras que post-link
funciones de post-link
se llaman child-then-parent
.
La función de pre-link
rara vez se utiliza, pero puede ser útil en escenarios especiales; por ejemplo, cuando un controlador secundario se registra a sí mismo con el controlador principal, pero el registro tiene que ser de un modo parent-then-child
( ngModelController
hace las cosas de esta manera).
No haga:
- Inspeccione elementos secundarios (es posible que aún no se hayan procesado, estén vinculados al alcance, etc.).