javascript - personalizadas - 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?
directivas personalizadas angularjs (3)
Por qué se necesitan controladores
La diferencia entre el link
y el controller
entra en juego cuando desea anidar directivas en su DOM y exponer funciones de la API de la directiva principal a las anidadas.
De los docs :
Mejores prácticas: use el controlador cuando quiera exponer una API a otras directivas. De lo contrario, use el enlace.
Digamos que quiere tener dos directivas my-form
y my-text-input
y quiere que my-text-input
directiva my-text-input
aparezca solo dentro de my-form
y en ninguna otra parte.
En ese caso, dirá al definir la directiva my-text-input
que requiere un controlador del elemento DOM parent
utilizando el argumento require
, como este: require: ''^myForm''
. Ahora el controlador del elemento padre se injected
en la función de link
como el cuarto argumento, siguiendo $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é utilizar el enlace en absoluto
No hay necesidad real de utilizar la función de link
si se está definiendo el controller
ya que $scope
está disponible en el controller
. Además, al definir tanto el link
como el controller
, es necesario tener cuidado con el orden de invocación de los dos (el controller
se ejecuta antes).
Sin embargo, de acuerdo con la forma Angular , la mayoría de las manipulaciones DOM y vinculaciones bidireccionales usando $watchers
usualmente se realizan en la función de link
mientras que la API para niños y $scope
manipulación se realiza en el controller
. Esta no es una regla difícil y rápida, pero al hacerlo, el código será más modular y ayudará a separar las preocupaciones (el controlador mantendrá el estado de la directive
y la función de link
mantendrá los enlaces externos del DOM
+).
Necesito realizar algunas operaciones en el alcance y la plantilla. Parece que puedo hacer eso en la función de link
o en la función del controller
(ya que ambos tienen acceso al alcance).
¿Cuándo es el caso cuando tengo que usar la función de link
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 el link
es el mundo no angular. Entonces, puedo usar $watch
, $digest
y $apply
.
¿Cuál es el significado de la función de link
, cuando ya teníamos el controlador?
Después de mi lucha inicial con las funciones de link
y controller
y de haber leído bastante sobre ellas, creo que ahora tengo la respuesta.
Primero vamos a entender ,
¿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, esta
templateString
está envuelta como un elemento angularvar el = angular.element(templateString);
Con
el
, ahora lo compilamos con$compile
para recuperar la función de enlace .var l = $compile(el)
Esto es lo que sucede,
-
$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 funciones de
link
. - Luego, todas las funciones de
link
se envuelven en una nueva función delink
y se devuelven comol
.
-
Finalmente, proporcionamos la función de
scope
a esta funciónl
(enlace) que además ejecuta las funciones de enlace envuelto con estescope
y sus elementos correspondientes.l(scope)
Esto agrega la
template
como un nuevo nodo alDOM
e invoca elcontroller
que agrega sus relojes al alcance que se comparte con la plantilla en DOM.
Comparando compilar 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 función de
compile
la directiva.Ahora, después de la compilación, tenemos la función de
link
que se ejecuta al unir 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 en función del alcance , etc.Finalmente, el controlador debe estar disponible para ser activo y reactivo mientras la directiva funciona en el
DOM
(después de conectarse). Por lo tanto:(1) Después de configurar la vista [ V ] (es decir, la plantilla) con el enlace.
$scope
es nuestro$controller
[ M ] y$controller
es nuestro [ C ] en MVC(2) Aproveche el enlace bidireccional con $ scope configurando relojes.
(3) Se espera agregar relojes
$scope
en el controlador ya que esto es lo que está viendo la plantilla durante el tiempo de ejecución.(4) Finalmente, el
controller
también se usa para poder comunicarse entre directivas relacionadas. (Como el ejemplo demyTabs
en https://docs.angularjs.org/guide/directive )(5) Es cierto que podríamos haber hecho todo esto en la función de
link
tambié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:
La función / objeto del controller
representa una abstracción model-view-controller (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, así que si necesita reaccionar a los cambios del Model
que vienen de View
the Controller
es la persona adecuada para hacer ese trabajo.
La historia sobre la función de link
es diferente, viene de una perspectiva diferente a MVC. Y es realmente esencial, una vez que queremos cruzar los límites de un controller/model/view
(plantilla) .
Comencemos con los parámetros que pasan a la función de link
:
function link(scope, element, attrs) {
- scope es un objeto de alcance angular.
- elemento es el elemento jqLite envuelto que coincide con esta directiva.
- attrs es un objeto con los nombres de atributos normalizados y sus valores correspondientes.
Para poner el link
en el contexto, debemos mencionar que todas las directivas están pasando por estos pasos del proceso de inicialización: compilar , vincular . Un extracto de Brad Green y Shyam Seshadri libro Angular JS :
Fase de compilación (una hermana de enlace, vamos a mencionarlo 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 según 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 que la vista sea dinámica, Angular ejecuta una función de enlace para cada directiva. Las funciones de enlace normalmente 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 usar el link
se puede encontrar aquí: docs . Vea el ejemplo: Crear una directiva que manipule el DOM , que inserta un "fecha y hora" en la página, actualizado cada segundo.
Solo un pequeño fragmento de esa rica fuente de arriba, que muestra la verdadera manipulación con DOM. Hay una función enganchada al $ timeout service, y también se borra en su llamada al destructor para evitar fugas 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);
});
...