La direttiva angularjs dovrebbe interagire direttamente con i servizi o è considerata un anti-pattern?


35

Quale è considerato migliore:

  • avere una direttiva che interagisce direttamente con i servizi

o

  • avere una direttiva che espone determinati hook a cui il responsabile del trattamento può vincolare il comportamento (che coinvolge servizi)?

Avrei bisogno di un po 'più di contesto su ciò che vuoi ottenere, cosa viene comunicato, quanto codice sorgente ci si deve aspettare qual è il tuo dominio, come deve ridimensionare?
Utente

È una direttiva responsabile del rendering di un widget per i commenti: visualizza il campo dei commenti, insieme ai pulsanti di invio / annullamento. Si suppone che questa direttiva sia utilizzata solo in un contesto: commentare "documento". Il modo in cui è attualmente gestito il controller sta esponendo le funzioni per la creazione di commenti effettivi (l'istanza iniettata dal controller ottiene il servizio commenti). L'altro modo di farlo è incapsulare il tutto (insieme alla gestione degli errori / dei successi) in una direttiva (la direttiva farebbe iniettare il servizio commenti).
WTK,

Risposte:


24

Una direttiva è la migliore (come regola empirica) quando è breve (dal punto di vista del codice), (potenzialmente) riutilizzabile e ha un ambito limitato in termini di funzionalità. Fare una direttiva che include l'interfaccia utente e dipende da un servizio (che presumo gestisce la connessione al back-end), non solo gli dà 2 ruoli funzionali, vale a dire:

  • Controllo dell'interfaccia utente per la visualizzazione / immissione dei dati per il widget.
  • Invio al back-end (tramite il servizio).

ma anche renderlo meno riutilizzabile, poiché non è possibile riutilizzarlo con un altro servizio o con un'interfaccia utente diversa (almeno non facilmente).

Quando prendo queste decisioni, spesso confronto con gli elementi HTML incorporati: ad esempio <input>, <textarea>oppure <form>: sono completamente indipendenti da qualsiasi backend specifico. HTML5 ha fornito <input>all'elemento alcuni tipi extra, ad esempio date, che è ancora indipendente dal back-end, e dove vanno esattamente i dati o come vengono utilizzati. Sono puramente elementi di interfaccia. I tuoi widget personalizzati, costruiti usando le direttive, penso che dovrebbero seguire lo stesso schema, se possibile.

Tuttavia, questa non è la fine della storia. Andando oltre l'analogia con gli elementi HTML incorporati, puoi creare direttive riutilizzabili che chiamano entrambi i servizi e utilizzare una direttiva puramente UI, proprio come potrebbe usare a <textarea>. Supponi di voler utilizzare un po 'di HTML nel modo seguente:

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

Per codificare la commentEntrydirettiva, è possibile creare una direttiva molto piccola che contenga solo il controller che collega un servizio con un widget UI. Qualcosa di simile a:

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

Portandolo all'estremo, potresti non aver mai bisogno di avere un ng-controllerattributo manuale nell'HTML: puoi fare tutto usando le direttive, purché ognuna abbia direttamente un ruolo "UI" chiaro o un ruolo "dati" chiaro.

C'è un aspetto negativo che dovrei menzionare: dà più "parti mobili" all'applicazione, il che aggiunge un po 'di complessità. Tuttavia, se ogni parte ha un ruolo chiaro ed è buona (unità + E2E testata), direi che ne vale la pena e un vantaggio complessivo a lungo termine.


59

Consentitemi di non essere d'accordo con la risposta di Michal Charemza.

Sebbene la sua risposta sia teoricamente corretta, non è molto pratica per il mondo reale.

Lo dico perché pensavo in quel modo e cercavo di applicarlo su una grande app del mondo reale che io e il mio team stiamo costruendo ed è diventato troppo problematico.

L'analogia con il linguaggio HTML non è buona, perché non dovresti sforzarti di costruire direttive generiche, estremamente riutilizzabili, perché non stai costruendo un'applicazione generica come un browser web.

Invece, dovresti usare le direttive per creare un DSL (Domain Specific Language) per la tua app, che risiede sul proprio dominio.

Ciò non significa che tutte le direttive non debbano essere generiche. Alcuni potrebbero esserlo, se è nella loro natura. Se stai creando un selettore di date personalizzato, rendilo sicuramente generico e riutilizzabile tra le app.

Ma se stai costruendo qualcosa come una casella di accesso che si lega al tuo back-end, fallo e basta.

L'unica regola empirica dovrebbe essere: non duplicare mai il codice (piccoli pezzi astratti in fabbriche e servizi) e renderlo testabile attraverso l'iniezione di dipendenza. Fortunatamente, con Angular, questi sono un gioco da ragazzi.

Mantienilo semplice. :)


5
Aspetti positivi Dema - anche se ho accettato la risposta di Michal, sono d'accordo con il tuo approccio, che non dovremmo saltare i cerchi per rendere qualcosa di riutilizzabile solo per il gusto di farlo. Quello era davvero il mio istinto iniziale, quello di legare il servizio alla direttiva, perché aveva un senso, non perché fosse il modo in cui il guru di angularjs avrebbe o non lo avrebbe fatto. Alla fine ho creato una direttiva con il servizio iniettato direttamente al suo interno e come API pubblica fornisco un hook per un callback che viene attivato dopo che i commenti sono stati effettivamente creati.
WTK,

2

Penso che la domanda "dovrebbe una direttiva interagire con un servizio" dipende da cosa sta facendo il tuo servizio.

Ho avuto direttive che interagiscono con servizi che non fanno nulla con le richieste HTTP e penso che sia un buon modello. I servizi / le fabbriche sono ottimi per incapsulare più logica orientata ai dati e le direttive sono ottimi per incapsulare la logica orientata alla presentazione. Lo scopo dichiarato dei servizi nei documenti angolari è: "Puoi utilizzare i servizi per organizzare e condividere il codice attraverso la tua app". È piuttosto ampio, ma i servizi possono essere utilizzati per raggiungere questo obiettivo nelle direttive.

Detto questo, capisco il desiderio in alcuni casi di farlo in modo che le direttive non facciano direttamente richieste HTTP. Ancora una volta, dipende dal servizio e da come stai organizzando i tuoi servizi.


1

Come da framework AngularJS, dovremmo singleton fabbriche / servizi per ottenere qualsiasi dato dal server. In modo che queste fabbriche possano essere riutilizzate attraverso l'applicazione senza riscrivere le stesse. Bene, all'interno della direttiva possiamo chiamare queste fabbriche per ottenere i dati recuperati da Api / server.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.