web-dev-qa-db-fra.com

La directive angularjs doit-elle interagir directement avec les services ou est-elle considérée comme un anti-modèle?

Lequel est considéré comme le meilleur:

  • avoir une directive qui interagit directement avec les services

ou

  • avoir une directive qui expose certains crochets auxquels le contrôleur peut lier le comportement (impliquant des services)?
36
WTK

Une directive est préférable (en règle générale) lorsqu'elle est courte (au niveau du code), (potentiellement) réutilisable et a une portée limitée en termes de fonctionnalité. Faire une directive qui inclut l'interface utilisateur et dépend d'un service (que je suppose gère la connexion au backend), ne lui donne pas seulement 2 rôles fonctionnels, à savoir:

  • Contrôle de l'interface utilisateur pour l'affichage/la saisie des données pour le widget.
  • Envoi au backend (via le service).

mais aussi de le rendre moins réutilisable, car vous ne pourrez plus le réutiliser avec un autre service, ou avec une interface utilisateur différente (du moins pas facilement).

Lorsque je prends ces décisions, je compare souvent les éléments HTML intégrés: par exemple <input>, <textarea> ou <form>: ils sont complètement indépendants de tout backend spécifique. HTML5 a donné le <input> élément quelques types supplémentaires, par exemple date, qui est toujours indépendant du backend, et où vont exactement les données ou comment elles sont utilisées. Ce ne sont que des éléments d'interface. Vos widgets personnalisés, construits à l'aide de directives, devraient, selon moi, suivre le même modèle, si possible.

Cependant, ce n'est pas la fin de l'histoire. En allant au-delà de l'analogie avec les éléments HTML intégrés, vous pouvez créer des directives réutilisables qui appellent à la fois des services et utiliser une directive purement UI, tout comme il pourrait utiliser un <textarea>. Supposons que vous souhaitiez utiliser du code HTML comme suit:

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

Pour coder la directive commentEntry, vous pouvez créer une très petite directive contenant uniquement le contrôleur qui relie un service à un widget UI. Quelque chose comme:

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
        });
      };
    }
  };
});

Poussant cela à l'extrême, vous n'aurez peut-être jamais besoin d'un manuel ng-controller attribut dans le HTML: vous pouvez tout faire en utilisant des directives, tant que chacune a directement un rôle "UI" clair ou un rôle "data" clair.

Il y a un inconvénient que je dois mentionner: cela donne plus de "pièces mobiles" à l'application, ce qui ajoute un peu de complexité. Cependant, si chaque partie a un rôle clair et est bien (testée à l'unité + E2E), je dirais que cela en vaut la peine et un avantage global à long terme.

24
Michal Charemza

Permettez-moi d'être en désaccord avec la réponse de Michal Charemza.

Bien que sa réponse soit théoriquement correcte, elle n'est pas très pratique pour le monde réel.

Je dis cela parce que je pensais comme ça et que j'essayais de l'appliquer sur une grande application du monde réel que moi-même et mon équipe construisons et c'est devenu trop gênant.

L'analogie avec le langage HTML n'est pas bonne, car vous ne devez pas vous efforcer de créer des directives générales, extrêmement réutilisables, car vous ne construisez pas une application générique comme un navigateur Web.

Au lieu de cela, vous devez utiliser les directives pour créer un langage spécifique au domaine (DSL) pour votre application, qui vit sur son propre domaine.

Cela ne signifie pas que toutes les directives ne doivent pas être génériques. Certains pourraient l'être, si c'est dans leur nature. Si vous créez un sélecteur de date personnalisé, rendez-le absolument générique et réutilisable dans toutes les applications.

Mais si vous construisez quelque chose comme une boîte de connexion qui se lie à votre back-end, faites-le.

La seule règle de base devrait être: ne jamais dupliquer de code (abstrait de petites pièces aux usines et services) et le rendre testable par injection de dépendance. Heureusement, avec Angular, ce n'est qu'un jeu d'enfant.

Rester simple. :)

60
Dema

Je pense que la question "si une directive doit interagir avec un service" dépend de ce que fait votre service.

J'ai eu des directives qui interagissent avec des services qui ne font rien avec les requêtes HTTP et je pense que c'est un bon modèle. Les services/usines sont parfaits pour encapsuler davantage de logique orientée données, et les directives sont idéales pour encapsuler une logique orientée présentation. L'objectif déclaré des services dans les documents Angular sont: "Vous pouvez utiliser des services pour organiser et partager du code dans votre application.". C'est assez large mais les services peuvent être utilisés pour atteindre cet objectif dans les directives .

Cela étant dit, je comprends le désir dans certains cas de faire en sorte que les directives ne fassent pas directement de requêtes HTTP. Encore une fois, cela dépend du service et de la façon dont vous organisez vos services.

2
ccnokes

Conformément au framework AngularJS, nous devrions singleton usines/services pour obtenir toutes les données du serveur. Afin que ces usines puissent être réutilisées à travers l'application sans réécrire la même chose. Bien à l'intérieur de la directive, nous pouvons appeler ces usines pour récupérer les données depuis Api/server.

1