Angular JS: ¿Cuál es la necesidad de la función de enlace de la directiva cuando ya teníamos el controlador de la directiva con alcance?

199

Necesito realizar algunas operaciones en el alcance y la plantilla. Parece que puedo hacer eso en la linkfunción o en la controllerfunción (ya que ambos tienen acceso al alcance).

¿Cuándo es el caso cuando tengo que usar la linkfunción y no el controlador?

angular.module('myApp').directive('abc', function($timeout) {
    return {
        restrict: 'EA',
        replace: true,
        transclude: true,
        scope: true,
        link: function(scope, elem, attr) { /* link function */ },
        controller: function($scope, $element) { /* controller function */ }
    };
}

Además, entiendo que linkes el mundo no angular. Entonces, puedo usar $watch, $digesty $apply.

¿Cuál es el significado de la linkfunción, cuando ya teníamos controlador?

Yugal Jindle
fuente
9
¿Qué quiere decir con " Además, entiendo que es el enlace mundo no angular. Por lo tanto, se puede utilizar $watch, $digesty $apply. "?
musically_ut
2
En el interior linkno vemos ninguna magia angular. es decir, no hay enlaces de 2 vías, etc. Solo que tenemos la API angular disponible para usar.
Yugal Jindle

Respuestas:

299

Después de mi primera lucha con el linky controllerfunciones y leyendo mucho acerca de ellos, creo que ahora tengo la respuesta.

Primero entendamos ,

Cómo funcionan las directivas angulares en pocas palabras:

  • Comenzamos con una plantilla (como una cadena o cargada en una cadena)

    var templateString = '<div my-directive>{{5 + 10}}</div>';

  • Ahora, esto templateStringestá envuelto como un elemento angular

    var el = angular.element(templateString);

  • Con el, ahora lo compilamos $compilepara recuperar la función de enlace .

    var l = $compile(el)

    Esto es lo que pasa

    • $compile recorre toda la plantilla y recopila todas las directivas que reconoce.
    • Todas las directivas que se descubren se compilan de forma recursiva y se recopilan sus linkfunciones.
    • Luego, todas las linkfunciones se envuelven en una nueva linkfunción y se devuelven como l.
  • Finalmente, proporcionamos scopefunciones a esta función l(enlace) que ejecuta aún más las funciones de enlace envueltas con este scopey sus elementos correspondientes.

    l(scope)

  • Esto agrega el templatecomo un nuevo nodo al DOMe invoca, lo controllerque agrega sus relojes al alcance que se comparte con la plantilla en DOM.

ingrese la descripción de la imagen aquí

Comparando compilación vs enlace vs controlador :

  • Cada directiva se compila solo una vez y la función de enlace se conserva para su reutilización. Por lo tanto, si hay algo aplicable a todas las instancias de una directiva, debe realizarse dentro de la compilefunción de la directiva .

  • Ahora, después de la compilación, tenemos una linkfunción que se ejecuta al adjuntar la plantilla al DOM . Por lo tanto, realizamos todo lo que es específico para cada instancia de la directiva. Por ejemplo: adjuntar eventos , mutar la plantilla según el alcance , etc.

  • Finalmente, el controlador debe estar disponible para ser vivo y reactivo mientras la directiva funciona en DOM(después de adjuntarse). Por lo tanto:

    (1) Después de configurar la vista [ V ] (es decir, la plantilla) con el enlace. $scopees nuestra [ M ] y $controlleres nuestra [ C ] en MVC

    (2) Aproveche el enlace bidireccional con $ scope configurando relojes.

    (3) $scopese espera que se agreguen relojes en el controlador ya que esto es lo que está mirando la plantilla durante el tiempo de ejecución.

    (4) Finalmente, controllertambién se utiliza para poder comunicarse entre directivas relacionadas. (Como myTabsejemplo en https://docs.angularjs.org/guide/directive )

    (5) Es cierto que podríamos haber hecho todo esto también en la linkfunción, pero se trata de la separación de las preocupaciones .

Por lo tanto, finalmente tenemos lo siguiente que se adapta perfectamente a todas las piezas:

ingrese la descripción de la imagen aquí

Yugal Jindle
fuente
55
También he encontrado este artículo útil para comprender el orden de ejecución aquí: lo esencial de las funciones de compilación y enlace dentro de las directivas de AngularJS
BobbyA
44
Gran explicación Me gustaría mencionar que se llama al controlador antes de la función de enlace.
jsbisht
38
controlador se ejecuta antes del enlace
Royi Namir
10
Me enfurece que Stack Overflow exija que las ediciones tengan al menos 6 caracteres, lo que no me permite corregir la ortografía de Let's en esta respuesta.
user1886323
79

Por qué se necesitan controladores

La diferencia entre linky controllerentra en juego cuando desea anidar directivas en su DOM y exponer las funciones API de la directiva principal a las anidadas.

De los documentos :

Mejor práctica: use el controlador cuando desee exponer una API a otras directivas. De lo contrario, use el enlace.

Supongamos que desea tener dos directivas my-formy my-text-inputdesea que las my-text-inputdirectivas aparezcan solo dentro my-formy en ningún otro lugar.

En ese caso, que va a decir mientras se define la directiva my-text-inputque requiere un controlador del parentelemento DOM utilizando el argumento requieren, como esto: require: '^myForm'. Ahora el controlador del elemento padre estará injecteden la linkfunción como el cuarto argumento, a continuación $scope, element, attributes. Puede llamar a funciones en ese controlador y comunicarse con la directiva principal.

Además, si no se encuentra dicho controlador, se generará un error.

¿Por qué usar link?

No hay una necesidad real de usar la linkfunción si se está definiendo, controllerya que $scopeestá disponible en controller. Además, al definir ambos linky controller, uno debe tener cuidado con el orden de invocación de los dos ( controllerse ejecuta antes).

Sin embargo, de acuerdo con la forma Angular , la mayoría de la manipulación DOM y el uso de enlace bidireccional $watchersgeneralmente se realiza en la linkfunción, mientras que la API para niños y la $scopemanipulación se realiza en el controller. Esta no es una regla difícil y rápida, pero hacerlo hará que el código sea más modular y ayudará a separar las preocupaciones (el controlador mantendrá el directiveestado y la linkfunción mantendrá los DOMenlaces externos +).

musically_ut
fuente
Eso es genial. Ahora, ¿me pueden ayudar con la segunda parte de la pregunta?
Yugal Jindle
Quiero decir, ya que teníamos el controlador que podría haber sido usado para comunicarse con otras directivas. Entonces, ¿cuál era la necesidad de link?
Yugal Jindle
1
Su respuesta de alguna manera no responde la pregunta real.
Yugal Jindle
1
¿Hay algún problema que ocurre cuando definimos a controller? ¿Por qué querré inventar una función completamente nueva solo para evitar definir un controlador?
Yugal Jindle
1
parece que el enlace de @scalaGirl ya no funciona
Minato
17

La controllerfunción / objeto representa un modelo de abstracción-vista-controlador (MVC). Si bien no hay nada nuevo que escribir sobre MVC, sigue siendo la ventaja más significativa de angular: dividir las preocupaciones en piezas más pequeñas. Y eso es todo, nada más, por lo que si necesita reaccionar ante los Modelcambios que vienen de Viewla personaController adecuada para hacer ese trabajo.

La historia sobre la linkfunción es diferente, proviene de una perspectiva diferente a la MVC. Y es realmente esencial, una vez que queremos cruzar los límites de una controller/model/view (plantilla) .

Vamos a comenzar con los parámetros que se pasan a la linkfunción:

function link(scope, element, attrs) {
  • El alcance es un objeto de alcance angular.
  • element es el elemento envuelto en jqLite con el que coincide esta directiva.
  • attrs es un objeto con los nombres de atributos normalizados y sus valores correspondientes.

Para poner el linkcontexto en contexto, debemos mencionar que todas las directivas están pasando por estos pasos del proceso de inicialización: compilar , vincular . Un extracto del libro de Brad Green y Shyam Seshadri Angular JS :

Fase de compilación (una hermana de enlace, mencionémosla aquí para obtener una imagen clara):

En esta fase, Angular recorre el DOM para identificar todas las directivas registradas en la plantilla. Para cada directiva, transforma el DOM en función de las reglas de la directiva (plantilla, reemplazar, transcluir, etc.) y llama a la función de compilación si existe. El resultado es una función de plantilla compilada,

Fase de enlace :

Para hacer que la vista sea dinámica, Angular ejecuta una función de enlace para cada directiva. Las funciones de enlace generalmente crean oyentes en el DOM o el modelo. Estos oyentes mantienen la vista y el modelo sincronizados en todo momento.

Un buen ejemplo de cómo usarlo linkse puede encontrar aquí: Creación de directivas personalizadas . Vea el ejemplo: Creación de una directiva que manipula el DOM , que inserta una "fecha-hora" en la página, que se actualiza cada segundo.

Solo un fragmento muy corto de esa rica fuente anterior, que muestra la manipulación real con DOM. Hay una función enganchada al servicio $ timeout, y también se borra en su llamada destructor para evitar pérdidas de memoria

.directive('myCurrentTime', function($timeout, dateFilter) {

 function link(scope, element, attrs) {

 ...

 // the not MVC job must be done
 function updateTime() {
   element.text(dateFilter(new Date(), format)); // here we are manipulating the DOM
 }

 function scheduleUpdate() {
   // save the timeoutId for canceling
   timeoutId = $timeout(function() {
     updateTime(); // update DOM
     scheduleUpdate(); // schedule the next update
   }, 1000);
 }

 element.on('$destroy', function() {
   $timeout.cancel(timeoutId);
 });

 ...
Radim Köhler
fuente
3
Pareces haber comparado compilery link. Se preguntan por qué linkcuando ya teníamoscontroller
Yugal Jindle
He extendido la respuesta para describir incluso el controlador con más detalles. Ahora los conceptos de los controllervs linkdeberían ser más claros ...
Radim Köhler
1
Puedo buscar conformarme con esa explicación. Pero parece estar algo borroso allí. Sería genial si alguien del equipo angular mismo puede hablar por él, proyectando hacia dónde lo ven: al linko al controller.
Yugal Jindle
1
Esa es la única parte que quiero entender (¿Cuándo no es suficiente?). Además, obtengo todos los beneficios de angular in controllery linkes relativamente feo. Entonces, el equipo angular debe tener una buena razón para ello en lugar de solo una opción.
Yugal Jindle
1
Pregunta: ¿Cuándo el controlador no es suficiente? Respuesta: Cuando necesite una experiencia fuera de Angular, como usar un complemento JQuery o usar la función JQlite como se menciona en el documento ( docs.angularjs.org/api/ng/function/angular.element:) , entonces necesitará enlace
Hasteq