Czy dyrektywa angularjs powinna bezpośrednio wchodzić w interakcje z usługami, czy też jest uważana za anty-wzór?


35

Który uważa się za lepszy:

  • posiadający dyrektywę, która bezpośrednio współdziała z usługami

lub

  • mając dyrektywę, która ujawnia pewne haczyki, z którymi kontroler może wiązać zachowanie (obejmujące usługi)?

Potrzebowałbym trochę więcej kontekstu tego, co chcesz osiągnąć, co jest przekazywane, ile kodu źródłowego należy się spodziewać, jaka jest twoja domena, w jaki sposób musi ona być skalowana?
Użytkownik

Jest to dyrektywa odpowiedzialna za renderowanie widżetu komentującego - wyświetla pole komentarza wraz z przyciskami wysyłania / anulowania. Ta dyrektywa ma być stosowana tylko w jednym kontekście - komentując „dokument”. Sposób, w jaki jest obecnie obsługiwany, kontroler udostępnia funkcje do tworzenia rzeczywistego komentarza (kontroler dostaje wstawioną instancję usługi komentarzy). Innym sposobem na zrobienie tego jest hermetyzacja całości (wraz z obsługą błędów / sukcesów) w dyrektywie (dyrektywa dostarczyłaby usługę komentarzy).
WTK

Odpowiedzi:


24

Dyrektywa jest najlepsza (jako ogólna zasada), gdy jest krótka (pod względem kodu), (potencjalnie) do ponownego użycia i ma ograniczony zakres pod względem funkcjonalności. Stworzenie dyrektywy, która zawiera interfejs użytkownika i zależy od usługi (zakładam, że obsługuje połączenie z backendem), nie tylko daje jej 2 funkcje funkcjonalne, a mianowicie:

  • Kontrolowanie interfejsu użytkownika w celu wyświetlania / wprowadzania danych dla widżetu.
  • Przesyłanie do zaplecza (za pośrednictwem usługi).

ale także sprawia, że ​​jest mniej przydatny do ponownego użycia, ponieważ nie można go ponownie użyć z inną usługą lub z innym interfejsem użytkownika (przynajmniej niełatwo).

Przy podejmowaniu tych decyzji, często w porównaniu do wbudowanego elementów HTML, na przykład <input>, <textarea>albo <form>: są one całkowicie niezależne od konkretnego zaplecza. HTML5 nadało temu <input>elementowi kilka dodatkowych typów, np. dateKtóre wciąż są niezależne od backendu i gdzie dokładnie idą dane lub jak są używane. Są to wyłącznie elementy interfejsu. Twoje niestandardowe widżety, zbudowane przy użyciu dyrektyw, myślę, że jeśli to możliwe, powinny stosować ten sam wzór.

To jednak nie koniec historii. Wychodząc poza analogię z wbudowanymi elementami HTML, możesz tworzyć dyrektywy wielokrotnego użytku, które wywołują usługi, i używać dyrektywy o czystym interfejsie użytkownika, tak jak może to zrobić <textarea>. Powiedz, że chcesz użyć kodu HTML w następujący sposób:

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

Aby zakodować commentEntrydyrektywę, możesz stworzyć bardzo małą dyrektywę, która zawiera tylko kontroler, który łączy usługę z widgetem interfejsu użytkownika. Coś jak:

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

Biorąc to do skrajności, być może nigdy nie będziesz musiał mieć ręcznego ng-controlleratrybutu w kodzie HTML: możesz to wszystko zrobić za pomocą dyrektyw, o ile każda z nich ma bezpośrednio rolę „interfejsu użytkownika” lub rolę „danych”.

Jest jedna wada, o której powinienem wspomnieć: daje więcej „ruchomych części” aplikacji, co dodaje nieco złożoności. Jeśli jednak każda część ma wyraźną rolę i ma się dobrze (testowana jednostka + E2E), argumentowałbym, że jest tego warta i przynosi ogólne korzyści w dłuższej perspektywie.


59

Pozwól mi nie zgodzić się z odpowiedzią Michała Charemzy.

Chociaż jego odpowiedź jest teoretycznie poprawna, nie jest bardzo praktyczna w prawdziwym świecie.

Mówię to, ponieważ tak myślałem i próbowałem wymusić to w dużej aplikacji z prawdziwego świata, którą buduję ja i mój zespół, a to stało się zbyt kłopotliwe.

Analogia do języka HTML nie jest dobra, ponieważ nie powinieneś dążyć do budowania dyrektyw o ogólnym przeznaczeniu, które można wielokrotnie wykorzystywać, ponieważ nie budujesz ogólnej aplikacji, takiej jak przeglądarka internetowa.

Zamiast tego należy użyć dyrektyw, aby zbudować język specyficzny dla domeny (DSL) dla aplikacji, który działa we własnej domenie.

Nie oznacza to, że wszystkie dyrektywy nie powinny być ogólne. Niektóre mogą być, jeśli jest to w ich naturze. Jeśli tworzysz niestandardowy selektor dat, z pewnością uczyń go ogólnym i można go ponownie używać w różnych aplikacjach.

Ale jeśli budujesz coś w rodzaju pola logowania, które łączy się z zapleczem, po prostu zrób to.

Jedyną ogólną zasadą powinno być: nigdy nie powielaj kodu (abstrakcyjne małe fragmenty do fabryk i usług) i nie pozwalaj na jego testowanie poprzez wstrzykiwanie zależności. Na szczęście w przypadku Angulara to bułka z masłem.

Nie komplikuj. :)


5
Dobre punkty Dema - chociaż zaakceptowałem odpowiedź Michała, zgadzam się z twoim podejściem, że nie powinniśmy przeskakiwać obręczy, aby zrobić coś wielokrotnego użytku dla samej korzyści. Tak naprawdę to był mój początkowy instynkt, aby związać służbę z dyrektywą, ponieważ to miało sens, a nie dlatego, że guru angularjs zrobiłby to lub nie zrobiłby. Ostatecznie stworzyłem dyrektywę z usługą wstrzykiwaną bezpośrednio do niej, a jako publiczny interfejs API udostępniam hak do wywołania zwrotnego, które jest uruchamiane po utworzeniu komentarzy.
WTK

2

Myślę, że pytanie „czy dyrektywa powinna wchodzić w interakcje z usługą” zależy od tego, co robi twoja usługa.

Miałem dyrektywy współpracujące z usługami, które nie robią nic z żądaniami HTTP i myślę, że to dobry wzorzec. Usługi / fabryki świetnie nadają się do enkapsulacji logiki zorientowanej na dane, a dyrektywy świetnie nadają się do enkapsulacji logiki zorientowanej na prezentację. Określony cel usług w dokumentach Angular to: „Możesz używać usług do organizowania i udostępniania kodu w swojej aplikacji”. To dość szerokie, ale usługi mogą zostać wykorzystane do osiągnięcia tego celu w dyrektywach.

Biorąc to pod uwagę, w niektórych przypadkach rozumiem pragnienie, aby dyrektywy nie wysyłały bezpośrednio żądań HTTP. Znowu zależy to od usługi i sposobu organizacji usług.


1

Zgodnie ze strukturą AngularJS powinniśmy singletonować fabryki / usługi w celu uzyskiwania dowolnych danych z serwera. Aby te fabryki mogły być ponownie wykorzystane w różnych aplikacjach bez przepisywania tego samego. Cóż, wewnątrz dyrektywy możemy zadzwonić do tych fabryk, aby pobrać dane z Api / serwera.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.