Quale è considerato migliore:
- avere una direttiva che interagisce direttamente con i servizi
o
- avere una direttiva che espone determinati hook a cui il controller può vincolare il comportamento (coinvolgendo servizi)?
Una direttiva è la migliore (come regola empirica) quando è breve (in termini di 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:
ma anche rendendolo meno riutilizzabile, in quanto non è possibile utilizzarlo di nuovo con un altro servizio o con un'interfaccia utente diversa (almeno non facilmente).
Quando prendi queste decisioni, mi confronto spesso con gli elementi HTML incorporati: ad esempio <input>
, <textarea>
o <form>
: sono completamente indipendenti da qualsiasi back-end specifico. HTML5 ha fornito l'elemento <input>
di alcuni tipi extra, ad es. 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, è possibile creare direttive riutilizzabili che chiamano entrambi i servizi e utilizzare una direttiva puramente UI, proprio come potrebbe utilizzare <textarea>
. Supponi di voler utilizzare un codice HTML come segue:
<document document-url="'documents/3345.html'">
<document-data></document-data>
<comments></comments>
<comment-entry></comment-entry>
</document>
Per codificare la direttiva commentEntry
, potresti creare una direttiva molto piccola che contiene solo il controller che collega un servizio con un widget dell'interfaccia utente. Qualcosa come:
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
});
};
}
};
});
Prendendo questo all'estremo, potresti non avere mai bisogno di avere un attributo ng-controller
manuale nell'HTML: puoi fare tutto usando le direttive, a patto che ognuna abbia direttamente un ruolo "UI" chiaro o una chiara ruolo "dati".
C'è un lato 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 è valida (unità + E2E testata), direi che ne vale la pena e un beneficio complessivo a lungo termine.
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 sto dicendo perché pensavo in quel modo e ho cercato di applicarlo su una grande app del mondo reale che io e il mio team stiamo costruendo ed è diventato troppo fastidioso.
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 utilizzare le direttive per creare una DSL (Domain Specific Language) per la tua app, che risiede nel proprio dominio.
Ciò non significa che tutte le direttive non dovrebbero essere generiche. Alcuni potrebbero essere, se è nella loro natura. Se stai creando un selettore di date personalizzato, rendilo assolutamente generico e riutilizzabile tra tutte le app.
Ma se stai creando 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 per fabbriche e servizi) e renderlo testabile tramite l'iniezione di dipendenza. Fortunatamente, con Angular, quelli sono un pezzo di torta.
Mantengalo semplice. :)
Penso che la domanda "se una direttiva interagisce 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 grandi per incapsulare una logica più orientata ai dati e le direttive sono ideali per incapsulare la logica orientata alla presentazione. Lo scopo dichiarato dei servizi nei documenti Angular è: "È possibile utilizzare i servizi per organizzare e condividere il codice attraverso l'app.". È piuttosto ampio, ma i servizi possono essere utilizzati per raggiungere questo obiettivo nelle direttive.
Detto questo, in alcuni casi capisco il desiderio di far sì che le direttive non facciano direttamente alcuna richiesta HTTP. Di nuovo, dipende dal servizio e da come stai organizzando i tuoi servizi.
Come da framework AngularJS, dovremmo singleton factories / services per ottenere qualsiasi dato dal server. In modo che queste fabbriche possano essere riutilizzate attraverso l'applicazione senza riscrivere le stesse. Bene all'interno di direttive possiamo chiamare queste fabbriche per ottenere dati recuperati da Api / server.
Leggi altre domande sui tag design-patterns patterns-and-practices angularjs