link directivas crear angularjs angularjs-directive

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:


¿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 de link forma nativa antes de que se llame la compile 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 de compile ).
  • Modifique la plantilla de origen para incluir el marcado deseado (en la función de compile ) y luego permita que ng-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.).