Статьи

Введение в футуристический новый маршрутизатор в AngularJS

AngularJS является одной из самых популярных платформ JavaScript MV * и широко используется для создания одностраничных приложений (SPA). Одна из сложных функций в SPA — маршрутизация. Маршрутизация на стороне клиента включает в себя изменение части представления и создание записи в истории навигации браузера. В качестве полнофункциональной клиентской среды AngularJS всегда поддерживала маршрутизацию через модуль ngRoute . Хотя этого достаточно для базовых маршрутов, он не поддерживает более сложные сценарии, такие как вложенные представления, параллельные представления или последовательность представлений.

В настоящее время разрабатывается новый маршрутизатор для Angular 2, и он будет перенесен на Angular 1.4. В этой статье мы увидим, как новый маршрутизатор можно использовать для определения маршрутов и как он решает некоторые проблемы, которые ngRoute не мог.

Как уже говорилось, на момент написания этой статьи работа над новым маршрутизатором все еще продолжается, и некоторые из API могут позже измениться. Команда Angular еще не додумалась до названия нового маршрутизатора, поэтому сейчас он называется футуристическим маршрутизатором.

Ограничения ngRoute

ngRoute не был создан с учетом сложных корпоративных приложений. Я лично видел приложения, в которых определенные части страницы должны быть загружены в несколько этапов. Такие приложения могут быть созданы с использованием ngRoute , но практически невозможно иметь состояние URL для каждого изменения, примененного к представлению.

Директива ng-view может использоваться только один раз внутри экземпляра директивы ng-app . Это мешает нам создавать параллельные маршруты, поскольку мы не можем одновременно загружать два параллельных представления.

Шаблон представления, отображаемый внутри ng-view не может содержать другую директиву ng-view . Это мешает нам создавать вложенные представления.

Новый маршрутизатор решает эти проблемы и предоставляет гибкий способ определения и использования маршрутов. Новый маршрутизатор также использует Controller as синтаксис . Я настоятельно рекомендую использовать Controller as синтаксиса, так как это одно из соглашений, которым необходимо следовать сегодня, чтобы подготовиться к Angular 2.

Создание простых маршрутов

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

Каждый маршрут, который будет добавлен к новому маршрутизатору, состоит из двух частей:

  • path : URL шаблона маршрута
  • component : комбинация шаблона и контроллера. По соглашению, контроллер и шаблон должны быть названы в честь компонента

Маршруты настраиваются с помощью службы $router . Поскольку $router является службой, мы можем определить маршруты в любом месте приложения (кроме провайдера или блока конфигурации). Однако нам нужно убедиться, что блок кода, определяющий маршруты, выполняется сразу после загрузки приложения. Например, если маршруты определены в контроллере (как мы скоро это сделаем), контроллер должен выполняться при загрузке страницы. Если они определены в сервисе, метод сервиса должен выполняться в блоке выполнения.

Давайте определим два простых маршрута и перейдем между ними, используя новый маршрутизатор. Если вы хотите следовать этому коду, вам необходимо получить копию нового маршрутизатора. Покажи мне как .

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

 mkdir new-router && cd new-router npm install angular-new-router 

Это создаст папку с именем node_modules в каталоге вашего проекта. Новый маршрутизатор можно найти по адресу node_modules/angular-new-router/dist/router.es5.min.js . Включите его в свой проект после самого AngularJS.

Прежде всего, давайте определим модуль и настроим маршруты:

 angular.module('simpleRouterDemo', ['ngNewRouter']) .controller('RouteController', ['$router', function($router){ $router.config([ { path:'/', redirectTo:'/first' }, { path:'/first', component:'first' }, { path:'/second/:name', component:'second' } ]); this.name='visitor'; }]) 

Контроллер в приведенном выше фрагменте определяет три маршрута. Обратите внимание, что корневой маршрут перенаправляет на наш первый шаблон и что третий маршрут принимает параметр в URL. Как видите, синтаксис задания параметра такой же, как и для ngRoute .

Как уже упоминалось, каждому компоненту требуется соответствующий шаблон представления и контроллер. По соглашению, имя контроллера должно быть именем компонента с суффиксом «Controller» (в нашем случае firstController и secondController ). Имя шаблона представления должно совпадать с именем компонента. Он также должен находиться в папке с тем же именем, что и компонент, внутри папки с именем components . Это даст нам:

 projectRoot/ components/ first/ first.html second/ second.html 

Эти соглашения могут быть переопределены с помощью $componentLoaderProvider . Мы увидим пример этого позже, а пока давайте придерживаться соглашений.

Далее идут виды для компонентов, которые были использованы в first и second . Мы определяем их в строке, используя директиву ng-template (чтобы мы могли воссоздать работающую демонстрацию), но в идеале они должны быть в отдельных файлах HTML:

 <script type="text/ng-template" id="./components/first/first.html"> <h3>{{first.message}}</h3> </script> <script type="text/ng-template" id="./components/second/second.html"> <h3>{{second.message}}</h3> </script> 

Как представления очень просты, так и контроллеры:

 angular.module('simpleRouterDemo') .controller('FirstController', function(){ console.log('FirstController loaded'); this.message = 'This is the first controller! You are in the first view.'; }) .controller('SecondController', function($routeParams){ console.log('SecondController loaded'); this.message = 'Hey ' + $routeParams.name + ', you are now in the second view!'; }); 

Поскольку оба этих контроллера созданы для использования с Controller as синтаксиса, они не принимают $scope . Служба $routeParams используется для получения значений параметров, переданных по маршруту.

Теперь нам нужно загрузить этот контроллер для регистрации маршрутов:

 <body ng-app=" simpleRouterDemo"  ng-controller="routeController as route" > </body> 

Наконец, нам нужно связать эти маршруты и загрузить их на страницу. Новый маршрутизатор ng-link директивы ng-link и ng-viewport , которые связывают представления и загружают шаблоны соответственно. Директива ng-viewport аналогична директиве ng-view ; это заполнитель для части вашего приложения, загружаемой динамически в зависимости от конфигурации маршрута.

В следующем фрагменте показано использование этих директив:

 <div class="col-md-3"> <ul class="nav"> <li> <a ng-link="first">First</a> </li> <li> <a ng-link="second({ name:route.name })">Second</a> </li> </ul> </div> <div class="col-md-9"> <ng-viewport></ng-viewport> </div> 

Работа с параллельными представлениями

Директива ng-viewport может использоваться любое количество раз внутри приложения. Следовательно, можно определить несколько параллельных представлений на странице. Окна просмотра должны иметь уникальные идентификаторы, чтобы загружать в них компоненты посредством определения маршрута.

В следующем фрагменте HTML показано, как включить несколько директив области просмотра:

 <div class="col-md-3"> <ul class="nav"> <li><a ng-href="#/{{route.name}}">First and Second</a></li> <li><a ng-href="#/swap/{{route.name}}">Second and First</a></li> </ul> </div> <div class="col-md-9"> <div class="col-md-6" ng-viewport="left"></div> <div class="col-md-6" ng-viewport="right"></div> </div> 

Представьте, что мы хотим поместить этот код в папку с именем parallel и шаблоны представления внутри parallel/components . Это даст нам:

 projectRoot/ parallel/ components/ first/ first.html second/ second.html 

Поскольку организация кода будет отличаться от соглашения (по умолчанию Angular ищет папку components в корне проекта), мы должны указать маршрутизатору искать представления в новой папке. Следующий блок конфигурации делает это:

 angular.module('parallelRouterDemo', ['ngNewRouter']) .config(['$componentLoaderProvider', function($componentLoaderProvider){ $componentLoaderProvider.setTemplateMapping(function (name) { return 'parallel/components/' + name + '/' + name + '.html'; }); }]) 

Маршруты для этой страницы должны загружать два компонента и отображать их в разных видовых экранах. Объект конфигурации использует уникальные идентификаторы видовых экранов, чтобы указать, где и где будет отображаться шаблон представления.

 $router.config([ { path: '/:name', component: { left: 'first', right: 'second' } }, { path: '/swap/:name', component: { left: 'second', right: 'first' } }, { path: '/', redirectTo: '/there' } ]) 

Управление жизненным циклом компонентов

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

  • canReactivate : указывает, можно ли повторно активировать представление. Его можно использовать для сохранения состояния представления и оптимизации времени загрузки представления при последующих запросах.
  • canActivate : canActivate перед активацией компонента. Активирует компонент, когда возвращается разрешенное обещание или true и отменяет в противном случае.
  • canDeactivate : запускается перед деактивацией компонента. Выгружает компонент, когда возвращается разрешенное обещание или true и отменяет в противном случае.

Использование методов жизненного цикла нового маршрутизатора делает жизнь проще, чем это было в Angular 1.x, так как нам не нужно обрабатывать агрегированные события в $scope для обнаружения события жизненного цикла.

Давайте рассмотрим, как canActivate метод canActivate на примере. Этот метод может использоваться, чтобы проверить, может ли пользователь получить доступ к представлению перед его загрузкой.

 this.canActivate = function(){ var hasAccess = userAccessInfo.hasAccessToSecondComponent; if(!hasAccess){ $window.alert('You don\'t have access to this view. Redirecting to previous view ...'); } return hasAccess; }; 

То же самое относится и к методу canDeactivate . Это может быть использовано для ограничения перехода пользователя со страницы с несохраненными изменениями.

 this.canDeactivate = function () { if (this.sampleText) { var alertResult = $window.confirm('You have unsaved changes. Do you want to leave the page?'); return alertResult; } return true; }; 

Примечание. Вы заметите, что в некоторых случаях предупреждение и диалог подтверждения запускаются дважды. Кажется, это ошибка в роутере, и я открыл проблему на GitHub .

Вывод

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