Отмена изменения пути в AngularJS

от автора

Давно полюбив Angular, я только сейчас добрался до блога автора фреймворка Dan Wahlin. А зря — там можно найти много интересных и нужных каждому приложению мыслей. Одну из них я и перевёл в этой статье. В ней вы узнаете как можно остановить переход на другую страницу в приложении Angular.


Словарь переводчика:
— view — шаблон
— route — маршрут, путь
— navigation — переход

Маршрутизация является отличным средством, которое позволяет с наименьшим количеством необходимого кода связать шаблоны с контроллерами AngularJS.
В то время как пользователь может переходить прямо к заданному пути, существует возможность того, что он инициирует переход до завершения какого-нибудь важного действия (например сохранение данных). В таких ситуациях Вы можете захотеть отменить переход и спросить пользователя, хочет ли он закончить свою работу или предупредить о потере его данных. В этой статье я хочу поговорить о приёме, который может быть использован для реализации такого задания.

Событие $locationChangeStart

Когда происходит переход в приложении AngularJS возникает несколько событий. Одно из них называется $locationChangeStart, а другое — $routeChangeStart (на самом деле существует ещё несколько). В настоящее время (версия 1.2) событие $routeChangeStart не предоставляет возможности отменить переход, зато $locationChangeStart вполне пригоден для этого. Если Вы посмотрите на код AngularJS, то найдёте следующий участок, который показывает возникновение события $locationChangeStart при вызове метода onUrlChange() объекта $browser:

$browser.onUrlChange(function (newUrl) {     if ($location.absUrl() != newUrl) {         if ($rootScope.$broadcast('$locationChangeStart', newUrl,              $location.absUrl()).defaultPrevented) {             $browser.url($location.absUrl());             return;         }         $rootScope.$evalAsync(function () {             var oldUrl = $location.absUrl();              $location.$$parse(newUrl);             afterLocationChange(oldUrl);         });         if (!$rootScope.$$phase) $rootScope.$digest();     } }); 

Самая важная часть кода — это вызов $broadcast. Этот вызов передаёт событие $locationChangeStart всем дочерним scope, благодаря чему они могут быть оповещены о смене location. Чтобы обработать это событие, Вы можете использовать функцию $rootScope.on(). Для примера я добавил обращение к $on() в функцию, которая вызывается сразу после запуска контроллера:

 function init() {          //initialize data here..     //Make sure they're warned if they made a change but didn't save it     //Call to $on returns a "deregistration" function that can be called to     //remove the listener (see routeChange() for an example of using it)     onRouteChangeOff = $rootScope.$on('$locationChangeStart', routeChange); } 

Этот код ожидает событие $locationChangeStart и вызывает функцию routeChange() при его возникновении. Возвращаемым значением функции $on является функция «отмены ожидания», которая может быть вызвана для того, чтобы прекратить ожидание события. В этом примере она называется onRouteChangeOff (доступна в контроллере). Очень скоро вы увидите как она используется.

Отмена перехода по маршруту

Callback-функция routeChange() срабатывает благодаря событию $locationChangeStart и показывает предупреждающее пользователя диалоговое окно:

Вот код функции routeChange():

function routeChange(event, newUrl) {     //Navigate to newUrl if the form isn't dirty     if (!$scope.editForm.$dirty) return;      var modalOptions = {         closeButtonText: 'Cancel',         actionButtonText: 'Ignore Changes',         headerText: 'Unsaved Changes',         bodyText: 'You have unsaved changes. Leave the page?'     };      modalService.showModal({}, modalOptions).then(function (result) {         if (result === 'ok') {             onRouteChangeOff(); //Stop listening for location changes             $location.path(newUrl); //Go to page they're interested in         }     });      //prevent navigation by default since we'll handle it     //once the user selects a dialog option     event.preventDefault();     return; } 

В параметрах этой функции Вы можете заметить объект события и новый маршрут, по которому пользователь пытается перейти. Так как до смены шаблона нужно напомнить пользователю о потере данных, объект события используется для отмены перехода. Обратите внимание на вызов event.preventDefault() в конце функции.
Диалоговое окно показано вызовом функции modalService.showModal() (взгляните на мой предыдущий пост о персонализированном modalService который работает обёрткой вокруг $modal сервиса из Angular UI Bootstrap).
Если пользователь выберет «Ignore Changes» то его изменения будут отменены и приложение перейдёт по необходимому маршруту. Это произойдёт благодаря отключению ожидания события $locationChangeStart вызовом функции onRouteChangeOff() (вспомните, что эта функция возвращена вызовом функции $on), так что мы не застрянем в бесконечном цикле появления диалогового окна при клике на кнопку «Ignore Changes».
Затем вызывается $location.path(newUrl) для обработки перехода к заданному шаблону. Если пользователь отменит действие, он останется на текущем шаблоне.

Выводы

Ключ к отмене перехода — это понимание принципа работы с событием $locationChangeStart.
Я надеюсь в будущем подобное задание можно будет решить и с помощью события $routeChangeStart, но на данный момент приведённый код выполняет эту работу в полном объёме.
Вы можете увидеть пример работы этого кода в приложении управления клиентами, которое доступно на Github (особенно шаблон customerEdit). Изучайте больше о приложении тут.

Интересны ли Вам переводы статей из блога Dan Wahlin?

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

Никто ещё не голосовал. Воздержался 1 человек.

ссылка на оригинал статьи http://habrahabr.ru/post/208346/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *