ngstyle - AngularJS: ¿Debo convertir la función de enlace de la directiva a un controlador?
ng-style angularjs (5)
ACTUALIZAR
(en la parte inferior agregué un código / plnkr que muestra el enfoque)
Aparte del artículo que mencionó: two , que básicamente no solo defiende el patrón que está solicitando, pero el componente basado en el front-end en general, he encontrado: http://joelhooks.com/blog/2014/02/11/lets-make-full-ass-angularjs-directives/ ( aboga por el uso mínimo de la función de enlace y el uso de ui-bootstrap como un ejemplo donde se ha utilizado dicho patrón). No puedo estar más de acuerdo con estos dos artículos.
Otra cosa sobre Angular2.0: no más $scope
en angular2.0 - https://www.youtube.com/watch?v=gNmWybAyBHI&t=12m14s , así que si puedes deshacerte de $scope
lo más posible, entonces la transición debería ser más suave.
También cometí un pequeño error:
Aún así, prefiero definir todas las funciones en el
controller
y simplemente llamarlas a través del alcance dellink
. Idealmente es solo una llamada:scope.init
ctrl.init(/*args*/)
(donde ctrl es el controlador de la directiva).
Hasta cierto punto, es una cuestión de gusto, pero hay algunas razones válidas para mantener la función de link
más delgada posible:
La lógica en la función de enlace no es fácilmente comprobable. Claro, puede compilar la directiva en sus pruebas unitarias y probar su comportamiento, pero la función de enlace en sí misma es una caja negra.
Si tiene que usar el
controller
(digamos, por ejemplo, la comunicación entre directivas), terminará con dos lugares donde colocar su código. Es confuso, pero si decide que la función delink
delgada, entonces todo lo que se puede poner en elcontroller
debe poner en elcontroller
.No puede inyectar dependencias adicionales directamente a la función de
link
(aún puede usar las inyectadas a la función de directiva principal). No hay tal problema en el caso del enfoque delcontroller
. Por qué importa:- Mantiene una mejor estructura del código, al tener las dependencias más cerca del contexto donde se necesitan.
- las personas que llegan a los fondos angulares con fondos distintos de JS todavía tienen problemas con el funcionamiento del cierre funcional en JS
Entonces, qué hay que poner en la función de enlace:
- Todo lo que debe ejecutarse después de que el elemento se haya insertado en DOM. Si el evento
$element
expuso$on(''linked'')
evento$on(''linked'')
que básicamente este punto no es válido. - Las referencias de agarre a los controladores
require:
ed. Nuevamente, si fuera posible inyectarlos directamente en elcontroller
...
Aún así, prefiero definir todas las funciones en el controller
y simplemente llamarlas a través del alcance del link
. Idealmente es solo una llamada: scope.init
.
Misko Hevery dijo un par de veces que DDO está lejos de ser perfecto y fácil de entender y evolucionó a lo que es ahora. Estoy bastante seguro de que si las decisiones de diseño se tomaran por adelantado, habría un solo lugar para poner la lógica de la directiva, ya que estará en angular2.0.
Ahora responda a su pregunta si debe convertir la función de link
a un controller
. Realmente depende de una serie de criterios, pero si el código se desarrolla activamente, probablemente valga la pena considerarlo. Mi experiencia (y un par de personas con las que hablé) se pueden ilustrar con esta imagen:
Acerca de angular2.0: va a ser un cambio tectónico, por lo que desde esa perspectiva no debería importar mucho, pero aún así el enfoque del controller
parece estar más cerca de la forma en que se van a declarar las directivas / componentes en v2. 0 a través de las clases de ES6.
Y como lo último: hasta cierto punto es cuestión de gustos, pero también existen algunas razones válidas para mantener la función CONTROLLER
(delegando la lógica a los servicios).
ACTUALIZACIÓN - PLNKR
PLNKR ejemplificando el enfoque:
html
<input ng-model="data.name"/>
<top-directive>
<my-directive my-config="data">
</my-directive>
</top-directive>
js
var app = angular.module(''plunker'', []);
app.controller(''MainCtrl'', function($scope) {
$scope.data = { name : ''Hello, World''};
});
app.controller(''MyCtrl'', function($scope){
var self = this;
this.init = function(top){
this.topCtrl = top;
this.getTopName = top.getName.bind(top);
this.getConfigName = function(){return this.config.name};
console.log(''initilizing'', this, $scope, this.getConfigName, this.getTopName());
}
// if you want to $watch you have to inject $scope
// you have access to the controller via name defined
// in contollerAs
$scope.$watch(''myCtrl.config'', function(){
console.log(''config changed'', self.getConfigName());
}, true);
});
app.directive(''topDirective'', function(){
return {
controller : function(){
this.name = "Hello, Top World";
this.getName = function(){return this.name};
}
}
});
app.directive(''myDirective'', function(){
return {
require: [''myDirective'', ''^topDirective''],
controller : ''MyCtrl'',
bindToController: true,
controllerAs: ''myCtrl'',
template : ''{{myCtrl.getConfigName() + " --- " + myCtrl.getTopName()}} '',
scope : {
config : "=myConfig",
},
link : function(scope, element, attrs, Ctrls){
Ctrls[0].init(Ctrls[1]);
}
}
});
He oído que es una buena práctica usar la sintaxis de controllerAs
junto con bindToController: true
en las directivas que usan un alcance aislado. Referencias: one , two
Supongamos, tengo una directiva como esta:
angular.module(''MyModule'').directive(''MyDirective'', function(User) {
return {
scope: {
name: ''=''
},
templateUrl: ''my-template.html'',
link: function(scope) {
scope.User = User;
scope.doSomething = function() {
// Do something cool
};
}
};
});
<!-- my-template.html -->
<div>
User Id: {{ User.id }}
Name: {{ name }}
<button ng-click="doSomething()">Do it</button>
</div>
Como puede ver, no hay un controlador en esta directiva. Pero, para poder aprovechar controllerAs
y bindToController: true
, tengo que tener un controlador.
¿Es la mejor práctica convertir la función de enlace a un controlador?
angular.module(''MyModule'').directive(''MyDirective'', function(User) {
return {
scope: {
name: ''=''
},
templateUrl: ''my-template.html'',
bindToController: true,
controllerAs: ''myCtrl'',
controller: function() {
this.User = User;
this.doSomething = function() {
// Do something cool
};
}
};
});
<!-- my-template.html -->
<div>
User Id: {{ myCtrl.User.id }}
Name: {{ myCtrl.name }}
<button ng-click="myCtrl.doSomething()">Do it</button>
</div>
Según tengo entendido, el controlador de la directiva debe usarse como un mecanismo para exponer la API de la directiva para una comunicación de directiva a directiva.
¿Alguien podría arrojar luz sobre cuál es la mejor práctica en estos días, teniendo en cuenta a Angular 2.0?
Comenzaré con tu última frase. Se trata de cómo quieres escribir tu código angular. Si desea seguir la pauta para escribir un buen código para angular 1.x, entonces no se moleste en pensar en lo que es ideal. Sin embargo, si desea prepararse para la próxima versión de Angular, así como para las próximas tecnologías web, le sugiero que comience a adoptar los nuevos conceptos y los ajuste a la forma en que escribe su código hoy. Tenga en cuenta que no hay correcto o incorrecto en este caso.
Hablando de angular 2.0 y ES6, me gustaría subrayar que la noción de directivas estará más en línea con la tecnología de componentes web.
En Angular 2.0 (según el diseño actual) se librará de la compleja forma de definir directivas; Eso no es más DDO. Por lo tanto, creo que sería mejor si empiezas a pensar de esa manera. Un componente solo tendrá una vista y un controlador.
Por ejemplo,
@ComponentDirective({
selector:''carousel'',
directives:[NgRepeat]
})
export class Carousel{
constructor(panes:Query<CarouselItem>) {
this.items= panes;
}
select(selectedCarouselItem:CarouselItem) { ... }
}
El código anterior está escrito en AtScript (un superconjunto de mecanografía y ES6), pero también podrá expresar lo mismo en ES5. Puedes ver cómo serán las cosas más simples. Hay en np tal noción como función de enlace o compilación, etc.
Además, la vista del componente anterior se vinculará directamente a la clase anterior; Así que ya puedes encontrar una similitud con la sintaxis del controlador.
Entonces, en esencia, sugeriría que primero veas la idea general detrás de los Componentes Web y cómo podría ser el futuro de los Desarrollos Web, y luego creo que comenzarías a escribir código Angular 1.x con eso en mente.
En resumen, intente codificar de una manera que favorezca la versión actual de Angular, pero si cree que hay algunas partes de su código que pueden abarcar algunos conceptos de la próxima versión, entonces hágalo. No creo que te haga daño. Trate de mantenerlo simple ya que la nueva versión de Angular será más simple.
Te sugiero que leas las siguientes publicaciones:
- https://www.airpair.com/angularjs/posts/component-based-angularjs-directives
- http://eisenbergeffect.bluespire.com/all-about-angular-2-0/
- https://www.airpair.com/angularjs/posts/preparing-for-the-future-of-angularjs
- http://teropa.info/blog/2014/10/24/how-ive-improved-my-angular-apps-by-banning-ng-controller.html
Considero que es una buena práctica mover el código de inicialización y / o exponer las funciones de la API dentro del controlador de una directiva, ya que cumple dos propósitos:
1. Intialization of $scope
2. Exposing an API for communication between directives
Inicialización de alcance
Supongamos que su directiva define un ámbito secundario (o hereda el ámbito). Si inicializa el ámbito dentro de su función de enlace, los ámbitos secundarios no podrán acceder a ninguna de las variables de alcance definidas aquí a través de la herencia del alcance. Esto se debe a que la función de enlace principal siempre se ejecuta después de la función de enlace principal. Por esta razón, el lugar adecuado para la inicialización del alcance está dentro de la función del controlador.
Exponer una API de controlador
Las directivas secundarias pueden acceder al controlador de la directiva principal a través de la propiedad ''require'' en el objeto de definición de directiva. Esto permite que las directivas se comuniquen. Para que esto funcione, el controlador principal debe estar completamente definido, de modo que se pueda acceder a él desde la función de enlace de la directiva secundaria. El mejor lugar para implementar esto es en la definición de la función del controlador. Las funciones del controlador principal siempre se llaman antes que las funciones del controlador secundario.
Pensamientos finales
Es importante entender que la función de enlace y la función del controlador tienen dos propósitos muy diferentes. La función del controlador se diseñó para la comunicación de inicialización y directiva, y la función del vinculador se diseñó para el comportamiento en tiempo de ejecución. Según la intención de su código, debe poder decidir si pertenece al controlador o si pertenece al enlazador.
¿Debería mover cualquier código que inicialice el alcance de la función de enlace a la función del controlador?
Sí, esa es una de las razones principales por las que existe la función del controlador: para inicializar el alcance y permitir que su alcance participe en la herencia del alcance prototípico.
¿Debe mover los controladores de $ watch de la función de enlace a la función del controlador?
No. El propósito de la función de enlace es conectar el comportamiento y potencialmente manipular el DOM. En la función de enlace, todas las directivas han sido compiladas y todas las funciones de enlace secundarias ya se han ejecutado. Esto lo convierte en un lugar ideal para el comportamiento de conexión, ya que está listo para DOM lo más cerca posible (no está realmente listo para DOM hasta después de la fase de Render).
Según la docs.angularjs.org/guide/directive más reciente docs.angularjs.org/guide/directive esta sigue siendo la práctica recomendada: "usar el controlador cuando se quiere exponer una API a otras directivas. De lo contrario, use el enlace". Me gustaría saber de otras personas también y el enfoque que están utilizando.
compartiendo los contenidos desde here , (no tengo la reputación suficiente para ponerlo como comentarios)
“where do I put code, in ''controller'' or ''link''?”
- Antes de la compilacion? - Controlador
- Después de la compilación? - Enlace
Couple of things to note:
el controlador ''$ scope'' y el enlace ''scope'' son la misma cosa. La diferencia es que los parámetros que se envían al controlador llegan a través de la inyección de dependencia (por lo que es necesario llamarlo ''$ scope''), donde los parámetros que se envían para vincular son funciones estándar basadas en orden. Todos los ejemplos angulares usarán ''alcance'' cuando esté en el contexto, pero generalmente lo llamo $ alcance por razones de cordura: http://plnkr.co/edit/lqcoJj?p=preview
El $ alcance / alcance en este ejemplo es simplemente el que se pasa desde el controlador principal.
''link'' en las directivas son en realidad la función ''post-link'' (vea el canal de renderización a continuación). Dado que el enlace previo rara vez se usa, la opción ''enlace'' es solo un atajo para configurar una función ''enlace posterior''.
Entonces, ¿cuál es un ejemplo del mundo real? Bueno, cuando estoy decidiendo, voy por esto:
- “¿Estoy haciendo plantillas y alcance las cosas?” - entra en el controlador
- "¿Estoy agregando una biblioteca de jQuery de coolbeans?"
El crédito por la respuesta es para jasonmore.