...

вторник, 7 января 2014 г.

[Перевод] Отмена изменения пути в 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). Изучайте больше о приложении тут.

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers.


Комментариев нет:

Отправить комментарий