Какой из них считается лучше:
- имея директиву, которая напрямую взаимодействует со службами
или
- иметь директиву, которая выставляет определенные ловушки, с которыми контроллер может связывать поведение (включая службы)?
Какой из них считается лучше:
или
Ответы:
Директива лучше всего (как правило), когда она короткая (с точки зрения кода), (потенциально) может использоваться повторно и имеет ограниченную область действия с точки зрения функциональности. Создание директивы, которая включает в себя пользовательский интерфейс и зависит от службы (которая, как я предполагаю, обрабатывает подключение к бэкэнду), не только дает ему 2 функциональные роли, а именно:
но также делает его менее пригодным для повторного использования, так как вы не сможете использовать его снова с другим сервисом или с другим пользовательским интерфейсом (по крайней мере, нелегко).
Принимая эти решения, я часто сравниваю со встроенными элементами HTML: например <input>
, <textarea>
или <form>
: они полностью независимы от какого-либо конкретного бэкэнда. HTML5 дал <input>
элементу несколько дополнительных типов, например date
, которые по-прежнему не зависят от бэкэнда, и куда именно идут данные или как они используются. Они являются чисто интерфейсными элементами. Ваши пользовательские виджеты, созданные с использованием директив, я думаю, должны следовать той же схеме, если это возможно.
Однако это не конец истории. Выйдя за пределы аналогии со встроенными элементами HTML, вы можете создавать директивы многократного использования, которые как вызывают службы, так и используют чисто директиву пользовательского интерфейса, точно так же, как она может использовать a <textarea>
. Скажем, вы хотите использовать HTML следующим образом:
<document document-url="'documents/3345.html'">
<document-data></document-data>
<comments></comments>
<comment-entry></comment-entry>
</document>
Чтобы кодировать commentEntry
директиву, вы можете создать очень маленькую директиву, которая просто содержит контроллер, который связывает сервис с UI-виджетом. Что-то типа:
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
});
};
}
};
});
Принимая это до крайности, вам, возможно, никогда не понадобится иметь ручной ng-controller
атрибут в HTML: вы можете делать все это с помощью директив, если у каждого из них есть четкая роль «пользовательского интерфейса» или роль «данных».
Следует отметить один недостаток: он дает больше «движущихся частей» приложению, что добавляет сложности. Тем не менее, если каждая часть имеет четкую роль и хорошо (проверено устройство + E2E), я бы сказал, что это того стоит, и общая выгода в долгосрочной перспективе.
Позвольте мне не согласиться с ответом Михала Чарамзы.
Хотя его ответ теоретически правильный, он не очень практичен для реального мира.
Я говорю это, потому что раньше я так думал и пытался применить его в большом приложении реального мира, которое создаем я и моя команда, и это стало слишком хлопотным.
Аналогия с языком HTML не очень хорошая, потому что вы не должны стремиться создавать универсальные директивы многократного использования, потому что вы не создаете универсальное приложение, такое как веб-браузер.
Вместо этого вы должны использовать директивы для создания доменного языка (DSL) для вашего приложения, которое живет в своем собственном домене.
Это не означает, что все директивы не должны быть общими. Некоторые могут быть, если это в их природе. Если вы создаете пользовательский инструмент выбора даты, во что бы то ни стало сделайте его универсальным и повторно используемым в разных приложениях.
Но если вы создаете что-то вроде поля входа в систему, которое привязывается к вашему бэкэнду, просто сделайте это.
Единственное эмпирическое правило должно заключаться в следующем: никогда не дублируйте код (абстрактные маленькие кусочки для фабрик и сервисов) и делайте его тестируемым посредством внедрения зависимостей. К счастью, с Angular это просто кусок пирога.
Будь проще. :)
Я думаю, что вопрос «должна ли директива взаимодействовать со службой» зависит от того, чем занимается ваша служба.
У меня были директивы, взаимодействующие со службами, которые ничего не делают с HTTP-запросами, и я думаю, что это хороший шаблон. Службы / фабрики отлично подходят для инкапсуляции логики, ориентированной на данные, а директивы - для инкапсуляции логики, ориентированной на представление. Заявленная цель служб в документации Angular: «Вы можете использовать службы для организации и совместного использования кода в вашем приложении». Это довольно широко, но службы могут быть использованы для достижения этой цели в директивах.
При этом я понимаю желание в некоторых случаях сделать так, чтобы директивы не делали напрямую HTTP-запросов. Опять же, это зависит от службы и от того, как вы организуете свои услуги.
В соответствии с инфраструктурой AngularJS, мы должны использовать отдельные фабрики / сервисы для получения любых данных с сервера. Таким образом, эти фабрики могут быть повторно использованы во всех приложениях без переписывания одного и того же. Внутри директивы мы можем вызывать эти фабрики для получения данных, получаемых с Api / сервера.