A diretiva angularjs deve interagir diretamente com os serviços ou é considerada um antipadrão?


35

Qual é considerado melhor:

  • ter uma diretiva que interaja diretamente com os serviços

ou

  • ter uma diretiva que exponha certos ganchos aos quais o controlador pode vincular o comportamento (envolvendo serviços)?

Eu precisaria de um pouco mais de contexto do que você deseja alcançar, do que é comunicado, quanto código-fonte é esperado, qual é o seu domínio, como ele deve ser dimensionado?
Utilizador

É uma diretiva responsável por renderizar um widget de comentários - exibe o campo de comentários, juntamente com os botões de envio / cancelamento. Esta diretiva deve ser usada apenas em um contexto - comentando "documento". A maneira como é manipulado atualmente o controlador está expondo funções para a criação de comentários reais (instância injetada do controller get do serviço de comentários). A outra maneira de fazer isso é encapsular a coisa toda (junto com o tratamento de erro / sucesso) em uma diretiva (a diretiva receberia o serviço de comentários injetado).
WTK

Respostas:


24

Uma diretiva é melhor (como regra geral) quando é curta (em termos de código), (potencialmente) reutilizável e tem um escopo limitado em termos de funcionalidade. A criação de uma diretiva que inclua interface do usuário e dependa de um serviço (que eu suponha que lida com a conexão com o back-end) não fornece apenas 2 funções funcionais, a saber:

  • Controlando a interface do usuário para exibição / entrada de dados para o widget.
  • Enviando para o back-end (através do serviço).

mas também tornando-o menos reutilizável, pois você não pode usá-lo novamente com outro serviço ou com uma interface do usuário diferente (pelo menos não facilmente).

Ao tomar essas decisões, costumo comparar com os elementos HTML internos: por exemplo <input>, <textarea>ou <form>: eles são completamente independentes de qualquer back-end específico. O HTML5 forneceu ao <input>elemento alguns tipos extras, por exemplo date, que ainda são independentes do back-end e para onde exatamente os dados vão ou como são usados. Eles são puramente elementos de interface. Seus widgets personalizados, criados usando diretivas, acho que devem seguir o mesmo padrão, se possível.

No entanto, este não é o fim da história. Indo além da analogia com os elementos HTML internos, você pode criar diretivas reutilizáveis ​​que chamam serviços e usam uma diretiva puramente de interface do usuário, assim como uma <textarea>. Digamos que você queira usar um pouco de HTML da seguinte maneira:

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

Para codificar a commentEntrydiretiva, você pode criar uma diretiva muito pequena que contenha apenas o controlador que vincula um serviço a um widget de interface do usuário. 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
        });
      };
    }
  };
});

Levando isso ao extremo, talvez você nunca precise ter um ng-controlleratributo manual no HTML: você pode fazer tudo isso usando diretivas, desde que cada uma tenha diretamente uma função clara de "UI" ou uma função clara de "dados".

Há uma desvantagem que devo mencionar: ela fornece mais "partes móveis" ao aplicativo, o que adiciona um pouco de complexidade. No entanto, se cada parte tem um papel claro e é bom (unidade + E2E testada), eu diria que vale a pena e um benefício geral a longo prazo.


59

Permitam-me que discorde da resposta de Michal Charemza.

Embora sua resposta seja teoricamente correta, não é muito prática para o mundo real.

Estou dizendo isso porque costumava pensar assim e tentei aplicá-lo em um aplicativo grande do mundo real que eu e minha equipe estamos construindo e isso se tornou muito problemático.

A analogia com a linguagem HTML não é boa, porque você não deve se esforçar para criar diretivas de uso geral, extremamente reutilizáveis, porque não está construindo um aplicativo genérico como um navegador da web.

Em vez disso, você deve usar as diretrizes para criar uma DSL (Linguagem Específica de Domínio) para seu aplicativo, que vive em seu próprio domínio.

Isso não significa que todas as diretivas não devam ser genéricas. Alguns podem ser, se é da natureza deles. Se você estiver criando um selecionador de data personalizado, torne-o genérico e reutilizável em todos os aplicativos.

Mas se você estiver criando algo como uma caixa de login que se liga ao seu back-end, faça-o.

A única regra prática deve ser: nunca duplique o código (abstraia pequenos fragmentos para fábricas e serviços) e torne-o testável através da injeção de dependência. Felizmente, com o Angular, esses são um pedaço de bolo.

Mantenha simples. :)


5
Bons pontos Dema - embora eu tenha aceitado a resposta de Michal, concordo com a sua abordagem, que não devemos pular arestas para tornar algo reutilizável apenas por isso. Esse foi realmente meu instinto inicial, vincular o serviço à diretiva, porque fazia sentido, não porque é como o angularjs guru's faria ou não faria isso. No final, criei uma diretiva com o serviço injetado diretamente nela e, como uma API pública, forneço um gancho para um retorno de chamada que é acionado após a criação dos comentários.
WTK 16/01

2

Eu acho que a pergunta "uma diretiva deve interagir com um serviço" depende do que seu serviço está fazendo.

Tive diretivas interagem com serviços que não fazem nada com solicitações HTTP e acho que é um bom padrão. Serviços / Fábricas são ótimos para encapsular uma lógica mais orientada a dados, e diretivas são ótimas para encapsular a lógica orientada à apresentação. O objetivo declarado dos serviços nos documentos angulares é: "Você pode usar serviços para organizar e compartilhar código em seu aplicativo". Isso é bastante amplo, mas os serviços podem ser usados ​​para atingir esse objetivo nas diretivas.

Dito isto, eu entendo o desejo em alguns casos de fazê-lo para que as diretivas não façam nenhuma solicitação HTTP diretamente. Novamente, isso depende do serviço e de como você está organizando seus serviços.


1

Conforme a estrutura do AngularJS, devemos escolher fábricas / serviços únicos para obter quaisquer dados do servidor. Para que essas fábricas possam ser reutilizadas em todos os aplicativos sem reescrever o mesmo. Bem, dentro da diretiva, podemos chamar essas fábricas para obter dados obtidos da API / servidor.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.