Всем привет. Эта статья писалась довольно долго, пару раз переписывалась заново, и, в итоге, меня не устроила. Уж слишком менторский получался тон. А тут, вдруг, грядет пятница, конец спринта, и значит, можно расслабиться. И так, не воспринимайте слишком серьезно, всего лишь несколько советов о том, как готовить фильтры в Angular.JS
Кому интересно или хочется немного расслабиться — вперед под кат и всем хорошей пятницы!
1. Используйте фильтры всегда и везде. Для заголовков страницы, названий колонок, списка товаров. Фильтры выполняются каждый дайджест, а значит, пользователь точно ничего упустит. Чем больше фильтров на странице – тем лучше. К тому же, потом, в каждый фильтр вы сможете добавить логики.
2. Делайте фильтры универсальными. Фильтр должен уметь фильтровать все. От товаров до embedded base-64. Всего один фильтр, каких-то двадцать параметров и ваша команда счастлива. Ведь все работает «из коробки», и писать ничего не надо. А если этот фильтр умеет еще и текст переводить в нижний регистр, то признание вас найдет. Неизбежно.
3. Всегда добавляйте в ваш фильтр логгирование. Так отлаживать намного проще. И, поверьте на слово, тот, кто будет разбирать ваши логи, точно не останется без работы.
4. Давайте фильтрам только общие названия. А вдруг его кто-то потом сделает универсальным! Не переименовывать же потом! К тому же так вашим коллегам будет гораздо интереснее читать разметку. Можно сказать, квест им подарите. Бесплатный.
5. Infinitie Scroll должен быть реализован только на фильтрах и никакой подгрузки данных. Сходили на сервер, выгрузили всю таблицу, а дальше пусть наши фильтры трудятся. Не зря же вы их писали. Нагрузка на сервер меньше, хостинг можно взять подешевле, а вам «благодарочка».
6. Бизнес логика должна быть только в фильтрах. Потому что – «И» — Инкапсуляция.
7. Вообще прячьте в фильтры всю логику. Так надежнее. А если не получается, то хотя бы самую «тяжелую». И чем тяжелее, тем лучше. Можно там всякие сложные расчеты производить или DOM менять. А еще лучше сервер дергать. Прямо из фильтра. Пользователь не поезд, подождет! Зато у вас будут самые тонкие сервисы и контроллеры. Как раз похвастаетесь на следующем собеседовании.
8. Кстати о DOM. Кто сказал, что для манипуляций с ним нужно использовать директивы? Фильтры, это лучшее место для $('#user_icon').trigger('click');
9. Коммуницируйте фильтры. Пусть один фильтр, что-то меняет во втором фильтре. Лучше всего через $broadcast. И лучше всего входящие данные. Так дебаг превратиться в веселую и занимательную игру, развивающую внимание, концентрацию и знание основ ядра Angular. И вообще, всегда используйте $broadcast. Это стильно.
10. Собирайте фильтры в цепочки! Если в цепочке меньше трех фильтров это не кошерно! Можно даже предложения фильтрами писать. Для коллег или просто любопытных пользователей.
11. Комбинируйте фильтры с ng-mouse-over. Это весело! Можно даже в хендлере mouse-over ничего не писать. Главное повесьте его на body и зачекиньте в пятницу вечером. Особенное удовольствие получите, если у вас Continues Integration.
12. Не оптимизируйте. Во-первых, ранняя оптимизация убивает. Во-вторых, это работа фреймворка. Вы же не будете делать чужую работу, правильно?
@By StGeass
13. Используйте фильтры как хэндлеры при изменении дайджеста!
14. Изменяйте контекст всего $scope прямо внутри фильтра через this. Ваша версия ангуляра не даёт этого сделать? Прокидывайте контекст прямо внутрь через аргументы и изменяйте снова!
И главное, знайте. Не фильтры тормозят ваше приложение. А непонимание и недооценка Вас, как разработчика!
.directive('onRepeatFinish', [function () {
return {
restrict: 'A',
link: function (scope, elem, attr) {
if (scope.$last === true) {
console.log('ngRepeatFinished');
};
}
}
}]);
Если что, вот «это» для параметризованных фильтров не работает.
Всем хорошей пятницы.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Комментарии (20)
EugeneSnihovsky
15.04.2016 13:15Ну не повезло автору с джунами в команде. Бывает, и не такое видели :)
StGeass
15.04.2016 13:27+1Дополню от себя встреченными на практике перлами:
13. Используйте фильтры как хэндлеры при изменении дайджеста!
14. Изменяйте контекст всего $scope прямо внутри фильтра через this. Ваша версия ангуляра не даёт этого сделать? Прокидывайте контекст прямо внутрь через аргументы и изменяйте снова!Drag13
15.04.2016 13:29+2C Вашего позволения дополню статью. Тринадцатый вариант явно для настоящих самураев.
StGeass
15.04.2016 13:41Да, пожалуйста.
Ещё добавлю от себя (по скольку тут не нашёл), что в новых версиях с фильтрами всё обстоит лучше в плане выполнения в каждом цикле, поскольку для них введено состояние stateless, по умолчанию все фильтры являются именно такими.
Приведу выдержку из так и не опубликованной статьи (хотя могу и полностью опубликовать, если для кого-то это будет полезным):
Динамические фильтры
Здесь речь пойдёт о фильтрах преимущественно завязанных на данных приходящих "извне" и не зависящих от выражения (
expression
) к которому привязан фильтр (filter
), например, фильтр который использует внутри себя некий сервис.
В версии до 1.3 фильтры были довольно глупыми и навешивая на выражение вотчер они постоянно заново вычисляли результат этого фильтра. Это одна из причин почему не стоит использовать множество фильтров в одном месте, нагружая лишней работой цикл
$digest
и одна из причин, почему новые фильтры работают быстрее. В новой версии фильтры ведут себя куда умнее и не вычисляют значение фильтра до тех пор, пока не изменится выражение к которому привязан данный фильтр.
Однако возникает проблема, как обновить значение фильтра, если оно зависит не только от выражения, но и от каких-то внешних факторов? Иными словами, как вернуть фильтру своё старое, "глупое" поведение, когда нам это нужно?
Для этого в 1.3 были введены понятия статичного (
stateless
) и динамического (stateful
) фильтров.
По умолчанию фильтр ведёт себя какstateless
. Сменить его поведение можно выставив нашему фильтру флаг$stateful
вtrue
.
Пример:
angular.module('myApp', []) .filter('customFilter', ['someService', function (someService) { function customFilter(input) { // манипуляция данными сторонним сервисом someService input += someService.getData(); return input; } customFilter.$stateful = true; return customFilter; }]);
Breaking change:
Внимательный читатель мог заметить, что такое изменение по сути может сломать поведение старых динамических фильтров. К сожалению, я забыл описать эту особенность в первой части, но такую возможность стоит учесть.
Drag13
15.04.2016 14:05Возможно я чего то понимаю но:
1. Я сейчас сижу на 1.4.8, статью перед публикацией проверял. Любой дайджест заставит выполниться фильтр. В том числе дайджест инициированный в другом контроллере. В чем улучшение?
2. Что должно заставить фильтр, манипулировать входящими данными? Почему нельзя обработать данные сервисом, и отдать фильтру только финальную последовательность?StGeass
15.04.2016 14:35+1Для демонстрации создал этот небольшой пример, как видно на примере, изменение stateful не ведёт к вызову stateless, и наоборот, изменение stateless вызывает срабатывание stateful фильтра, при том что обычный stateless фильтр отрабатывает только один раз.
- Ну на вскидку, у нас есть динамический список №1 и в одном из мест где его надо выводить, есть некий чёрный список №2 через который этот первый список фильтруется, при этом сам чёрный список тоже зависит от того что у нас в №1. Разумеется, всё это можно написать так, чтобы отдать в фильтр конечные данные, а не вызывать получение чёрного списка №2 внутри непосредственно фильтра, но случаи разные бывают, как и извращенцы, поэтому такая возможность разработчиками учтена :)
Demogor
16.04.2016 11:10Ой, да зачем так все сложно-то?
while (true){var callLogic=()=>{… callLogic();}; setInterval(()=>callLogic (),1)}
Нет cpu-нет проблем.
wir_wolf
Такое чуство что автор стати фильтровый маньяк. Эдак и бизнес логику, и запросы к серваку, все в фильтрах. Бесспорно, фильтры классная вещь, но это уже черезчур. Человек который пройдет в команду с таким проектом явно будет иметь некие сложности с освоением структуры проекта.
Drag13
Некоторые сложности будут, но скорее от непривычки. Все пройдет. Потом :)
garex
Афтар забыл в самом начале повесить тег САРКАЗМ.
Drag13
Надеюсь :)
kstep
В сети всегда найдётся человек, который воспримет сарказм дословно.