Tutorial de AngularJS: Desmitificación de directivas personalizadas

Publicado: 2022-03-11

Con el rápido crecimiento de JavaScript como lenguaje de pila completa, cada vez más aplicaciones utilizan marcos que permiten que el navegador web maneje una mayor parte del procesamiento de la interfaz de usuario, como el enlace de datos, la gestión de vistas de datos, la transformación de datos y muchos otros servicios. Uno de los marcos más capaces, extensibles y populares es AngularJS, y uno de los componentes más útiles del marco AngularJS es algo llamado directiva . AngularJS proporciona muchas directivas útiles y, lo que es más importante, proporciona un marco completo para crear directivas personalizadas.

¿Qué es una directiva? En pocas palabras, las directivas son funciones de JavaScript que manipulan y agregan comportamientos a los elementos HTML DOM. Las directivas pueden ser muy simples o extremadamente complicadas. Por lo tanto, obtener una comprensión sólida de sus muchas opciones y funciones que los manipulan es fundamental.

En este tutorial, se explorarán las cuatro funciones que se ejecutan cuando se crea una directiva y se aplican al DOM y se proporcionarán ejemplos. Esta publicación asume cierta familiaridad con AngularJS y directivas personalizadas. Si es nuevo en Angular, puede disfrutar de un tutorial sobre cómo crear su primera aplicación AngularJS.

Las cuatro funciones del ciclo de vida de la directiva AngularJS

Hay muchas opciones que se pueden configurar y la forma en que esas opciones se relacionan entre sí es importante. Cada directiva pasa por algo similar a un ciclo de vida a medida que AngularJS compila y vincula el DOM. El ciclo de vida de la directiva comienza y finaliza dentro del proceso de arranque de AngularJS, antes de que se represente la página. En el ciclo de vida de una directiva, hay cuatro funciones distintas que pueden ejecutarse si están definidas. Cada uno permite al desarrollador controlar y personalizar la directiva en diferentes puntos del ciclo de vida.

Las cuatro funciones son: compilar , controlador , pre-enlace y post-enlace .

La función de compilación permite que la directiva manipule el DOM antes de compilarlo y vincularlo, lo que le permite agregar/eliminar/cambiar directivas, así como agregar/eliminar/cambiar otros elementos del DOM.

La función de controlador facilita la comunicación directiva. Los directivos de hermanos e hijos pueden solicitar al controlador de sus hermanos y padres que comuniquen información.

La función previa al enlace permite la manipulación privada de $scope antes de que comience el proceso posterior al enlace.

El método post-enlace es el principal método de trabajo de la directiva.

En la directiva, se lleva a cabo la manipulación DOM posterior a la compilación, se configuran los controladores de eventos, al igual que los relojes y otras cosas. En la declaración de la directiva, las cuatro funciones se definen así.

 .directive("directiveName",function () { return { controller: function() { // controller code here... }, compile: { // compile code here... return { pre: function() { // pre-link code here... }, post: function() { // post-link code here... } }; } } })

Por lo general, no se necesitan todas las funciones. En la mayoría de las circunstancias, los desarrolladores simplemente crearán una función de controlador y enlace posterior siguiendo el patrón a continuación.

 .directive("directiveName",function () { return { controller: function() { // controller code here... }, link: function() { // post-link code here... } } })

En esta configuración, enlace se refiere a la función post-enlace .

Ya sea que todas o algunas de las funciones estén definidas, su orden de ejecución es importante, especialmente su ejecución en relación con el resto de la aplicación AngularJS.

Ejecución de función de directiva AngularJS en relación con otras directivas

Considere el siguiente fragmento HTML con las directivas parentDir , childDir y grandChildDir aplicadas al fragmento HTML.

 <div parentDir> <div childDir> <div grandChildDir> </div> </div> </div>

El orden de ejecución de las funciones dentro de una directiva, y en relación con otras directivas, es el siguiente:

  • Fase de compilación
    • Función de compilación : parentDir
    • Función de compilación : childDir
    • Función de compilación : grandChildDir
  • Fase de controlador y preenlace
    • Función del controlador : parentDir
    • Función de preenlace: parentDir
    • Función del controlador : childDir
    • Función de enlace previo: childDir
    • Función del controlador : grandChildDir
    • Función de enlace previo: grandChildDir
  • Fase posterior al enlace
    • Función posterior al enlace : grandChildDir
    • Función posterior al enlace : childDir
    • Función posterior al enlace : parentDir

El tutorial de la función de directiva de AngularJS: orden de ejecución en relación con otras directivas.

Explicación de la función directiva de AngularJS: Inmersión profunda

La fase de compilación ocurre primero. Esencialmente, la fase de compilación adjunta detectores de eventos a los elementos DOM. Por ejemplo, si un elemento DOM en particular está vinculado a una propiedad $scope , el detector de eventos que permite que se actualice con el valor de la propiedad $scope se aplica al elemento DOM. El proceso de compilación comienza con el elemento DOM raíz desde el cual se arrancó la aplicación AngularJS y atraviesa las ramas del DOM utilizando un recorrido transversal en profundidad, compilando primero un padre y luego sus hijos hasta los nodos hoja.

Una vez que se completa la compilación, ya no se pueden agregar ni eliminar directivas del DOM (aunque hay una forma de evitar esto usando directamente el servicio de compilación. La siguiente fase es la llamada de controladores y funciones de enlace previo para todas las directivas. Cuando el controlador se llama, el $scope está disponible y se puede usar. El $elemento inyectado en el controlador contiene la plantilla compilada pero no incluye el contenido secundario transcluido (el contenido transcluido es el contenido entre las etiquetas HTML de inicio y finalización en las que se encuentra la directiva). Por definición, los controladores en un patrón MVC simplemente pasan el modelo a la vista y definen funciones para manejar eventos. Por lo tanto, el controlador de una directiva no debe modificar el DOM de la directiva por dos razones: viola el propósito de la controlador, y el contenido secundario transcluido no se ha agregado al DOM. Entonces, ¿qué hace un controlador más allá de modificar el alcance de $ ? El controlador permite que las directivas secundarias se comuniquen con wi las directivas de los padres. La función de controlador en sí debe considerarse como un objeto de controlador que se pasará a la función de enlace posterior de la directiva secundaria si la directiva secundaria lo solicita. Por lo tanto, el controlador generalmente se usa para facilitar la comunicación de directivas mediante la creación de un objeto con propiedades y métodos que pueden usar sus directivas hermanas y secundarias. La directiva principal no puede determinar si una directiva secundaria puede requerir su controlador, por lo que es mejor limitar el código en este método a las funciones y propiedades que las directivas secundarias pueden usar de manera segura.

Después de la función de controlador, se ejecuta la función de enlace previo. La función de preenlace es un misterio para mucha gente. Si lee gran parte de la documentación en Internet y en libros, la gente escribe que esta función se usa solo en circunstancias excepcionales y que la gente casi nunca la necesitará. Esas mismas explicaciones no dan un ejemplo de una situación en la que podría usarse.

La función de preenlace realmente no es nada complicada. Primero, si revisa el código fuente de AngularJS, encontrará un excelente ejemplo de la función de enlace previo: la directiva ng-init la usa. ¿Por qué? Es simplemente un gran método para ejecutar código privado que involucra $scope ; código que no puede ser llamado por directivas de hermanos y niños. A diferencia de la función de controlador, la función de enlace previo no se pasa a las directivas. Por lo tanto, puede usarse para ejecutar código que modifica el $scope de su directiva. La directiva ng-init hace exactamente esto. Cuando se ejecuta la función de enlace previo para ng-init , simplemente ejecuta el JavaScript pasado a la directiva contra el $scope de la directiva. El resultado de la ejecución está disponible a través de la herencia prototípica de $scope a las directivas secundarias durante las ejecuciones de funciones de controlador, preenlace y postenlace, pero sin dar acceso a esas directivas secundarias para volver a ejecutar el código en el controlador anterior del padre. función de enlace Además, es posible que la directiva deba ejecutar otro código no relacionado con el $scope que desea mantener en privado.

Algunos desarrolladores experimentados de AngularJS dirían que este código privado aún podría colocarse en el controlador y luego no ser llamado por las directivas secundarias. Ese argumento sería válido si la directiva solo la usará el desarrollador original que la codificó, pero si la directiva va a ser distribuida y reutilizada por otros desarrolladores, encapsular el código privado en la función de enlace previo podría ser muy beneficioso. Dado que los desarrolladores nunca saben cómo se reutilizará su directiva a lo largo del tiempo, proteger el código privado para que no sea ejecutado por una directiva secundaria es un buen enfoque para la encapsulación del código de directiva. Considero que es una buena práctica colocar el código público de comunicación directiva en la función de controlador y el código privado en la función de preenlace. Al igual que el controlador, el vínculo previo nunca debe manipular el DOM ni ejecutar una función de transclusión, ya que el contenido de las directivas secundarias aún no se ha vinculado.

Para cada directiva, su función de controlador y enlace previo se ejecuta antes que la función de controlador y enlace previo de sus directivas secundarias. Una vez que se completa la fase de controlador y enlace previo para todas las directivas, AngularJS comienza la fase de enlace y ejecuta las funciones posteriores al enlace para cada directiva. La fase de vinculación se ejecuta de forma opuesta a los flujos de ejecución de compilación, controlador y previnculación, comenzando con los nodos del DOM hoja y avanzando hasta el nodo DOM raíz. El recorrido del DOM posterior al enlace sigue una ruta principalmente en profundidad. A medida que se vincula cada directiva secundaria, se ejecuta su función posterior al vínculo.

La función post-link es la función más comúnmente implementada en las directivas personalizadas de AngularJS. En esta función, se puede hacer casi cualquier cosa razonable. El DOM se puede manipular (solo para sí mismo y para los elementos secundarios), $scope está disponible, se puede usar el objeto controlador para las directivas principales, se pueden ejecutar funciones de transclusión, etc. Sin embargo, existen algunas limitaciones. No se pueden agregar nuevas directivas al DOM porque no se compilarán. Además, todas las manipulaciones DOM deben realizarse mediante funciones DOM. Simplemente llamar a la función html en el elemento DOM y pasar el nuevo HTML eliminará todos los controladores de eventos agregados durante el proceso de compilación. Por ejemplo, estos no funcionarán como se esperaba:

 element.html(element.html());

o

 element.html(element.html() + "<div>new content</div>");

El código no hará que cambie el HTML, pero reasignar la versión de cadena de los elementos DOM eliminará todos los controladores de eventos creados durante el proceso de compilación. Por lo general, la función de enlace posterior se usa para conectar controladores de eventos, $ watches y $observes .

Una vez que se ejecutan todas las funciones posteriores al enlace, $scope se aplica a la estructura DOM compilada y enlazada, y la página de AngularJS cobra vida.

Cuadro de funciones directivas

Aquí hay un gráfico que enumera el propósito de cada función, lo que está disponible cuando se ejecuta y las mejores prácticas sobre cómo usar cada función de manera adecuada.

Ejecución
Pedido
Directiva
Función
DOM transcluir $alcance Llamable
por niño
1 compilar El DOM no se ha compilado, pero la plantilla se ha cargado en el área de contenido del elemento DOM. Se pueden agregar y eliminar directivas. DOM se puede manipular con funciones DOM y reemplazo de cadenas HTML. La función Transclude está disponible pero está en desuso y no se debe llamar. No disponible. La función no puede ser llamada por elementos secundarios.
2 controlador El elemento DOM compilado está disponible pero no debe modificarse. El contenido secundario transcluido no se ha agregado al elemento DOM. No se deben producir cambios de DOM porque se trata de un controlador y el contenido secundario transcluido aún no se ha vinculado. La función Transclude está disponible pero no debe llamarse. $scope está disponible y se puede utilizar. Los parámetros de función se inyectan mediante el servicio $injector . La función se pasa a funciones de enlace de directivas secundarias y es invocable por ellas.
3 enlace previo El elemento DOM compilado está disponible, pero no debe modificarse porque los elementos DOM de la directiva secundaria aún no se han vinculado. La función Transclude está disponible pero no debe llamarse. $scope está disponible y se puede modificar. Las directivas secundarias no pueden llamar a la función. Pero puede llamar a los controladores de las directivas de los padres.
4 enlace posterior El elemento DOM compilado y los elementos DOM de directiva secundaria están disponibles. DOM se puede modificar solo con funciones DOM (sin reemplazo de HTML) y solo se puede agregar contenido que no requiere compilación. No se permite agregar/eliminar directivas. La función Transclude está disponible y se puede llamar. $scope está disponible y se puede utilizar. Los hijos de las directivas no pueden invocarlo, pero pueden llamar al controlador de las directivas principales.

Resumen

En este tutorial sobre las directivas de AngularJS, hemos aprendido sobre el propósito, el orden de ejecución y las capacidades y usos generales de cada una de las cuatro funciones directivas: compilar , controlador , enlace previo y enlace posterior . De las cuatro funciones, el controlador y el enlace posterior son las más utilizadas, pero para directivas más complejas que necesitan tener un mayor control del DOM o necesitan un entorno de ejecución de alcance privado, se pueden utilizar las funciones de compilación y enlace previo.