Я работаю над небольшим фрагментом кода, который обрабатывается внутри директивы. Директиве передается большой объект данных, который разделяется на типы и подтипы. Используя выпадающие списки, пользователь должен иметь возможность выбирать, какую часть данных они хотят видеть на дисплее, и он должен быть динамическим, что означает, что по мере изменения их выбора данные будут немедленно обновляться. Моя первая попытка сделать это - поставить код в контроллер, прикрепленный к директиве.
Использование контроллера, прикрепленного к директиве
Посмотреть
<select ng-model="type" ng-change="updateDisplay()">
<option value="typeOne">One</option>
<option value="typeTwo">Two</option>
<option value="typeThree">Three</option>
</select>
<select ng-model="subType" ng-change="updateDisplay()">
<option value="subTypeOne">One</option>
<option value="subTypeTwo">Two</option>
<option value="subTypeThree">Three</option>
</select>
...
<div ng-repeat="(key, value) in selectedData">
{{key}}, {{value}}
</div>
контроллер
$scope.type = 'typeOne';
$scope.subType = 'subTypeOne';
$scope.selectedData = null;
$scope.updateDisplay = function() {
//$scope.data is a large object of data passed into the directive, but not important to define for this post
$scope.selectedData = $scope.data[$scope.type][$scope.subType];
}
$scope.updateDisplay(); // call on page load to populate with defaults
Этот подход работает отлично, но мне было предложено, что это не правильный "угловой" способ и что все это должно быть отложено на службу. В этом случае не только данные должны быть переданы моей директиве, но и все сервисные методы. В раскрывающихся списках выбора нам нужно будет поместить вызов ng-change, чтобы служба узнала, что значение изменилось и нуждается в обновлении
ng-change="setSelectedType({type:type})"
а затем, возможно, потребуется выполнить еще одну функцию после запуска функции "Сеттер", чтобы пересчитать динамическое значение для выбранных данных. (эквивалент выполнения updateDisplay() выше.
Мой общий вопрос заключается в том, что перемещение всей этой логики на службу даже имеет смысл? Я должен был бы написать getters и seters со стороны службы и называть их каждый раз по ng-change в дополнение к тому, чтобы служба затем возвращала отфильтрованные данные. И наоборот, если это делается в контроллере, нам не нужно создавать какие-либо "сеттеры/геттеры" для переменных, потому что они привязаны к области и обновляются автоматически. (и для меня весь смысл использования каркаса как углового).
Не сделав этот вопрос ТОО самоуверенным, может ли кто-то с Угловым опытом говорить об этом?
Я не вижу в вашем примере никакой логики. Я согласен с тем, что бизнес-логика лучше всего находится в сервисе, потому что она помогает черному ящику использовать эту логику из аспекта отображения приложения.
Я думаю, что угловой способ - использовать наблюдателей.
scope.$watch('subType',function(subType) {
scope.selectedData = data[scope.type || 'defaultKey'][subType || 'defaultKey'];
});
Нет необходимости иметь функцию updateData или вызывать ее при загрузке страницы, потому что наблюдатели будут выполняться хотя бы один раз во время первого дайджеста.
Другая проблема - scope.data
и если это действительно должно быть в области. Если в шаблоне нет прямого связывания с ним, то не оставляйте его вне области видимости. Это помогает сохранить масштаб, связанный с тем, что в шаблоне. Позже, когда вы отлаживаетесь в браузере и смотрите на область $($0).scope()
вы увидите только то, что важно.
Если у вас есть data
в области. Вы могли бы просто сделать это. Угловая ошибка не будет отсутствовать. Шаблон будет просто не повторяться, если выбор не будет действительным.
<div ng-repeat="(key, value) in data[type][subType]">
{{key}}, {{value}}
</div>
Лично я не верю в жесткие и быстрые правила развития, но, как правило, большинство разработчиков согласятся:
Положите это так: что вы собираетесь делать, если решите, что хотите повторно использовать свою директиву на другой странице или в другом контроллере? Теперь вам нужно перезаписать весь код, который был в вашем первом контроллере.
Если вы использовали услугу, вы просто вводите директиву и услугу в свой новый контроллер (и связываете их через контроллер) - работа выполнена!
Наконец, вы хотите ограничить взаимодействие между директивой и контроллером с четко определенным интерфейсом. Используйте свойство "scope" в директиве для этого.
controller as
синтаксиса, а не наносить вред$scope
. Это намного чище, легче читать и безопаснее для будущего