DRY роутинг в AngularJS

в 20:07, , рубрики: AngularJS, best practice, javascript, routing, метки: , , ,

Настройка роутинга в Angular JS — не самая сложная штука. Поэтому я лишь предлагаю одно из возможных решений, которое поможет вам придерживаться принципа “don't repeat yourself” при работе с маршрутами.

DRY роутинг в AngularJS

Во-первых хочу призвать создавать URL-адреса в стили a-ля REST. Такое соглашение внутри команды пригодиться, когда проект значительно вырастит.

Допустим наш сайт продаёт корм для животных.
Тогда URL’ы будут выглядеть следующим образом:
Список кормов — /!#/dogfoods
Страница “корма” — /!#/dogfood/:id
Какая-то дополнительная информация по корму — /!#/dogfood/:id/details

Если вы не знаете, зачем нужен /!#/ — вам сюда. Если кратко — такие ссылки считаются seo-френдли для аяксовых сайтов.

Теперь давайте поговорим о том, что я считаю “сухим” роутингом. Всё просто — это когда url’ы лежат в константах. Вот и вся идея.

Для этого достаточно положить список url’ов в .constant. Назовём его ROUTES.

.constant('ROUTES', (function () {

        return {
            DOGFOODS: /dogfoods,
            DOGFOOD: /dogfood/:id,
            DOGFOOD_DETAILS: /dogfood/:id/details
        }
    })())

Теперь конфигурируем роутинг:

.config(['$routeProvider', 'ROUTES', function ($routeProvider, ROUTES) {
        var pathToIncs = '/pages/'; //папка, в которой лежат шаблоны

        $routeProvider.when(ROUTES.DOGFOODS, {templateUrl: pathToIncs + dogfoods.html', controller: dogfoodsCtrl'});
        $routeProvider.when(ROUTES.DOGFOOD, {templateUrl: pathToIncs + dogfood.html', controller: dogfoodCtrl'});
        $routeProvider.when(ROUTES.DOGFOOD_DETAILS, {templateUrl: pathToIncs + dogfood_details.html', controller: dogfoodsDetailsCtrl'});
}])

Окей, должно работать. Возможно сейчас это и выглядит излишне, но сейчас мы будем использовать наши константы повторно.
Например главное меню нашего сайта. В html-шаблоне пишем просто:

<a href="ROUTES.DOGFOODS">Dogfoods list</a> 

Ну как, обретает всё смысл? Теперь все урлы в одном месте, меньше работы руками в если надо будет что то переименовать. Да и появляется поддержка со стороны IDE.

Ах да, небольшой момент. Поскольку мы не знаем в каком scope нам понадобятся константы url’ов, нам надо положить их в rootScope. Лично мне это не кажется загрязнением скопов — URL'ам там самое место.

Сделать это можно например так:

.run(['$rootScope', 'ROUTES', function ($rootScope, ROUTES) {
        $rootScope.ROUTES = ROUTES;
}])

Так же я предлагаю завести себе такой вот сервис:

factory('redirectFactory', ['$location', 'ROUTES', function ($location, ROUTES) {        
return {
            goDogfoods: function () {
                $location.path(ROUTES.DOGFOODS);
            }            
        };
    }])

Название сервиса redirectFactory говорит само за себя — делать редиректы, например из контроллера, или других сервисов, например при авторизации, логауте и т.п.

Так, я уже вижу что в меня летят какашки. Действительно, как быть с параметризироваными урлами? Тут нам на помощь придут фильтры.
Допустим параметром у нас будет язык. Например я хочу получить url’ы вида /!#/eng/dogfoods.
Модифицируем наши константы ROUTES:

.constant('ROUTES', (function () {
     var langParam = '/:lang';

        return {
            DOGFOODS: langParam +  /dogfoods,
            ...
        }
    })())

Создадим фильтр routeFilter:

.filter('routeFilter', ['$filter', function (localeFactory, $filter) {
        return function (route) {
            var langParam = '/:lang';
            var langVal = ‘/*тут мы подставляем параметр*/’;
            return route.replace(langParam, langParam.replace(langParam, '/' + langVal));
        };
    }])

Отлично, теперь делаем просто вот так:

<a href="/#!{{ROUTES.DOGFOODS | 'routeFilter'}}">Dogfoods list</a> 

Правда после этого фильтр придётся применять и в js.
Например вот так будет выглядеть наш сервис redirectFactory:

.factory('redirectFactory', ['$location', 'ROUTES', '$filter', function ($location, ROUTES, $filter) {
        var 'routeFilter' = $filter('routeFilter');

return {
            goDogfoods: function () {
                $location.path(routeFilter(ROUTES.DOGFOODS));
            },
           ...
    }])

Вот пожалуй и всё.

Заключение

Чего сейчас не хватает Angular JS, так это сборника рецептов и best practice. Уверен, что всё можно обыграть более изящно, ведь всегда есть куда стремиться, так? Но я просто хотел добавить ещё один рецепт в копилку. Надеюсь что описное мной вам пригодиться.

Автор: Light241

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js