Nested routing в AngularJS

    image
    В AngularJS, как известно, нет возможности штатными средствами сделать многоуровневую маршрутизацию, в которой перезагрузка нижних уровней маршрутов бы не приводила к пересозданию элементов верхнего уровня. Стандартный сервис $route инициализирует вид, контроллер и его scope целиком каждый раз, когда изменяется URL страницы.

    Для решения этой проблемы написано несколько сторонних решений, включая известный ui-router. По ряду причин ни одно из решений для некоторых моих проектов не подошло, и я написал собственную библиотеку, которую здесь и представляю: angular-route-segment.

    Что она позволяет делать?

    Демонстрационный пример здесь: angular-route-segment.com/src/example
    Исходники примера в каталоге example на Гитхабе.

    Библиотека служит заменой стандартному сервису $route. Каждый маршрут представляется в виде иерархической древовидной цепочки сегментов, перечисленных через точку, каждый из которых возможно конфигурировать в отдельности.

    angular.module('app').config(function ($routeSegmentProvider) {
    
    $routeSegmentProvider.
    
        when('/section1',          's1.home').
        when('/section1/prefs',    's1.prefs').
        when('/section1/:id',      's1.itemInfo.overview').
        when('/section1/:id/edit', 's1.itemInfo.edit').
        when('/section2',          's2').
    
        segment('s1', {
            templateUrl: 'templates/section1.html',
            controller: MainCtrl}).
    
        within().
    
            segment('home', {
                templateUrl: 'templates/section1/home.html'}).
    
            segment('itemInfo', {
                templateUrl: 'templates/section1/item.html',
                controller: Section1ItemCtrl,
                dependencies: ['id']}).
    
            within().
    
                segment('overview', {
                    templateUrl: 'templates/section1/item/overview.html'}).
    
                segment('edit', {
                     templateUrl: 'templates/section1/item/edit.html'}).
    
                up().
    
            segment('prefs', {
                templateUrl: 'templates/section1/prefs.html'}).
    
            up().
    
        segment('s2', {
            templateUrl: 'templates/section2.html',
            controller: MainCtrl});
    


    Допускается использовать и иной синтаксис, без прохода по дереву:

    $routeSegmentProvider.segment('s1', {
        templateUrl: 'templates/section1.html',
        controller: MainCtrl});
    
    $routeSegmentProvider.within('s1').segment('home', {
        templateUrl: 'templates/section1/home.html'});
    
    $routeSegmentProvider.within('s1').segment('itemInfo', {
        templateUrl: 'templates/section1/item.html',
        controller: Section1ItemCtrl,
        dependencies: ['id']});
    


    С помощью директивы app-view-segment (замена штатному ng-view) указывается место в DOM страницы, куда каждый из уровней сегментов должен быть отрендерен:

    index.html
    <ul>
        <li><a href="/section1">Section 1</a></li>
        <li><a href="/section2">Section 2</a></li>
    </ul>
    <div id="contents" app-view-segment="0"></div>
    


    section1.html (будет загружен в элемент div#contents)
    <h4>Section 1</h4>
    Section 1 contents.
    <div app-view-segment="1"></div>
    


    В этот может быть загружен следующий сегмент, и так далее.

    Такой подход, в сочетании с некоторыми продвинутыми фичами по конфигурированию, позволяет делать довольно сложные вещи с маршрутизацией в приложении.
    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 19
    • +1
      Как раз искал красивое решение для этой проблемы, чтобы не создавать тучу флагов состояния внутри $scope.
      • 0
        Все круто, но имеет место реализация тут www.bennadel.com/blog/2441-Nested-Views-Routing-And-Deep-Linking-With-AngularJS.htm с вашим решением, быть схожей? Я не говорю, что это то же самое, просто подход.
        • 0
          Да, это я тоже видел. Подход близок, реализация иная.
        • 0
          Будьте добры опишите, что не устроило в ui-router.
          • 0
            Да, было интересно.
            • +1
              Они перегрузили библиотеку функциональностью. Для моих задач нужно просто дерево вложенных друг в друга view, завязанных на стандартный роутинг, а не сложная концепция отдельно стоящих state. То есть я не хотел забивать микроскопом гвозди. Больше кода — больше багов, тем более что ui-router до сих пор не в релизном состоянии, а мой код отлажен на реальных проектах уже достаточно хорошо.
              • 0
                А также обратите внимание на параметры сегмента watcher, untilResolved, resolveFailed. Т.е. инструмент заточен не только с точки зрения, что отсутствует все ненужное. Но еще добавлено нужное.

                Извечный вопрос универсального vs созданного под свои нуждны. Почти все, что брали у angular-ui, потом каким-то образом дотачивали под свои нужды. Объемы кода все же не те, когда не стоит браться за свою реализацию.
              • 0
                Не совсем понял: Иерархия ограничена только 2 уровнями вложенности?
                • 0
                  Ну почему же — кто мешает добавить в цепочку еще .segment(...)?
                  • 0
                    Смотрите пример — там показаны три.
                    • 0
                      Спасибо. Не обратил внимания.
                  • 0
                    Скажите пожалуйста, поддерживается ли вложенный роутинг в режиме HTML5 ($locationProvider.html5Mode(true), который без '#')?
                    • 0
                      Библиотека использует стандартный $route, поэтому всего его фичи поддерживаются.
                      • 0
                        Cпасибо, посмотрю либу:) Ui-router, например, почему-то этот режим не поддерживал, когда я его пытался прикрутить. Решил вопрос, кажется, при помощи фильтров:)
                    • 0
                      Вы продолжаете поддерживать библиотеку?
                      • 0
                        Скажите, а можно ли с помощью Вашей реализации изменить parent state без перегрузки всех его child'ов?
                        • 0
                          Если я правильно вас понял, то да, можно — посмотрите на пример в статье, там есть контролы на каждом уровне. Можно изменять состояние контрола и смотреть, что будет происходить при навигации в нижних уровнях.
                          • 0
                            Спасибо, обязательно попробую.
                        • 0
                          Подскажите, можно ли использовать параметр из dependencies в resolve функции? Если да, то как? В вашем примере вы используете параметр только в контроллере.

                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.