Пользователь
0,0
рейтинг
14 августа 2013 в 23:39

Разработка → 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>


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

Такой подход, в сочетании с некоторыми продвинутыми фичами по конфигурированию, позволяет делать довольно сложные вещи с маршрутизацией в приложении.
Артём @artch
карма
161,3
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (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 функции? Если да, то как? В вашем примере вы используете параметр только в контроллере.

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