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