¿Debería la directiva angularjs interactuar directamente con los servicios o se considera un antipatrón?

35

Cuál se considera mejor:

  • Tener una directiva que interactúa con los servicios directamente

o

  • ¿Tiene una directiva que expone ciertos ganchos a los que el controlador puede vincular el comportamiento (que involucra servicios)?
WTK
fuente
Necesitaría un poco más de contexto de lo que desea lograr, lo que se comunica, cuánto código fuente se espera, cuál es su dominio, cómo tiene que escalar?
Usuario
Es una directiva responsable de representar un widget de comentarios: muestra el campo de comentarios, junto con los botones de enviar / cancelar. Se supone que esta directiva debe usarse solo en un contexto: comentar sobre "documento". La forma en que se maneja actualmente el controlador está exponiendo funciones para crear comentarios reales (instancia del servicio de comentarios inyectados por el controlador get). La otra forma de hacerlo es encapsular todo (junto con el manejo de errores / éxito) en una directiva (la directiva recibiría el servicio de comentarios inyectado).
WTK

Respuestas:

24

Una directiva es mejor (como regla general) cuando es corta (en cuanto a código), (potencialmente) reutilizable, y tiene un alcance limitado en términos de funcionalidad. Hacer una directiva que incluye la interfaz de usuario y depende de un servicio (que supongo que maneja la conexión con el backend), no solo le da 2 funciones funcionales, a saber:

  • Controlar la interfaz de usuario para la visualización / entrada de datos para el widget.
  • Envío al backend (a través del servicio).

pero también lo hace menos reutilizable, ya que no puede volver a usarlo con otro servicio o con una IU diferente (al menos no fácilmente).

Al tomar estas decisiones, a menudo me comparo con los elementos HTML integrados: por ejemplo <input>, <textarea>o <form>: son completamente independientes de cualquier backend específico. HTML5 le ha dado al <input>elemento algunos tipos adicionales, por ejemplo date, que aún es independiente del backend, y dónde van exactamente los datos o cómo se usan. Son puramente elementos de interfaz. Sus widgets personalizados, construidos usando directivas, creo que deberían seguir el mismo patrón, si es posible.

Sin embargo, este no es el final de la historia. Yendo más allá de la analogía con los elementos HTML incorporados, puede crear directivas reutilizables que llaman a los servicios y usar una directiva puramente de interfaz de usuario, al igual que podría usar a <textarea>. Digamos que quiere usar algo de HTML de la siguiente manera:

<document document-url="'documents/3345.html'">
 <document-data></document-data>
 <comments></comments>
 <comment-entry></comment-entry>
</document>

Para codificar la commentEntrydirectiva, puede crear una directiva muy pequeña que solo contenga el controlador que vincula un servicio con un widget de interfaz de usuario. Algo como:

app.directive('commentEntry', function (myService) {
  return {
    restrict: 'E',
    template: '<comment-widget on-save="save(data)" on-cancel="cancel()"></comment-widget>',
    require: '^document',
    link: function (scope, iElement, iAttrs, documentController) {
      // Allow the controller here to access the document controller
      scope.documentController = documentController;
    },
    controller: function ($scope) {
      $scope.save = function (data) {
        // Assuming the document controller exposes a function "getUrl"
        var url = $scope.documentController.getUrl(); 

        myService.saveComments(url, data).then(function (result) {
          // Do something
        });
      };
    }
  };
});

Llevando esto al extremo, es posible que nunca necesite tener un ng-controlleratributo manual en el HTML: puede hacerlo todo utilizando directivas, siempre que cada una tenga directamente una función clara de "interfaz de usuario" o una función clara de "datos".

Hay un inconveniente que debo mencionar: le da más "partes móviles" a la aplicación, lo que agrega un poco de complejidad. Sin embargo, si cada parte tiene un papel claro y está bien (unidad + E2E probado), diría que vale la pena y que es un beneficio general a largo plazo.

Michal Charemza
fuente
59

Permítame estar en desacuerdo con la respuesta de Michal Charemza.

Aunque su respuesta es teóricamente correcta, no es muy práctica para el mundo real.

Lo digo porque solía pensar así y traté de aplicarlo en una gran aplicación del mundo real que mi equipo y yo estamos construyendo y simplemente se volvió demasiado problemático.

La analogía con el lenguaje HTML no es buena, porque no debes esforzarte por construir directivas extremadamente reutilizables, porque no estás creando una aplicación genérica como un navegador web.

En su lugar, debe usar las directivas para crear un lenguaje específico de dominio (DSL) para su aplicación, que viva en su propio dominio.

Eso no significa que todas las directivas no deberían ser genéricas. Algunos podrían ser, si está en su naturaleza. Si está creando un selector de fecha personalizado, hágalo genérico y reutilizable en todas las aplicaciones.

Pero si está creando algo así como un cuadro de inicio de sesión que se vincula a su back-end, simplemente hágalo.

La única regla general debería ser: no duplicar nunca el código (pequeñas piezas abstractas para fábricas y servicios) y hacerlo comprobable mediante inyección de dependencia. Afortunadamente, con Angular, son pan comido.

Mantenlo simple. :)

Dema
fuente
55
Puntos positivos Dema: aunque acepté la respuesta de Michal, estoy de acuerdo con tu enfoque, de que no deberíamos saltar los aros para hacer que algo sea reutilizable por el simple hecho de hacerlo. Ese fue mi instinto inicial realmente, vincular el servicio con la directiva, porque tenía sentido, no porque es cómo lo haría o no lo haría angularjs guru. Al final, creé una directiva con el servicio inyectado directamente en ella y, como API pública, proporciono un enlace para una devolución de llamada que se activa después de que se crean los comentarios.
WTK
2

Creo que la pregunta "si una directiva debe interactuar con un servicio" depende de lo que esté haciendo su servicio.

He tenido directivas que interactúan con servicios que no hacen nada con las solicitudes HTTP y creo que es un buen patrón. Los Servicios / Fábricas son excelentes para encapsular lógica más orientada a datos, y las directivas son excelentes para encapsular lógica orientada a presentaciones. El propósito declarado de los servicios en los documentos de Angular es: "Puede usar los servicios para organizar y compartir código en su aplicación". Eso es bastante amplio, pero los servicios se pueden utilizar para lograr ese objetivo en las directivas.

Dicho esto, entiendo el deseo en algunos casos de hacerlo para que las directivas no realicen ninguna solicitud HTTP directamente. Nuevamente, depende del servicio y de cómo esté organizando sus servicios.

ccnokes
fuente
1

Según el marco de trabajo de AngularJS, deberíamos crear fábricas / servicios para obtener cualquier información del servidor. Para que estas fábricas se puedan reutilizar en la aplicación sin tener que volver a escribir la misma. Bueno, dentro de la directiva podemos llamar a estas fábricas para obtener datos que se obtienen de Api / server.

Basavaraj Kabuure
fuente