Подтвердить что ты не робот

Угловой JS подтвердить перед изменением маршрута

Возможно ли прослушивание изменений маршрута и onwindowunload как для подтверждения отпуска страницы без сохранения изменений?

Варианты использования:

  • Пользователь нажимает Назад
  • Пользователь нажимает кнопку "Назад" в браузере.
  • Типы пользователей в другом URL

Если пользователь нажимает "отменить", остановите изменение страницы/маршрута.

Я видел несколько разных примеров, но никто не работал совершенно правильно.

4b9b3361

Ответ 1

Демо: http://plnkr.co/edit/Aq8uYg

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

Слушайте $locationChangeStart и используйте event.preventDefault(), чтобы отменить изменение местоположения, если изменения не подтверждены.

Этот метод имеет одно преимущество перед $route.reload(): текущий контроллер и модели не будут повторно создаваться. таким образом, все ваши переменные сохраняются так же, как пользователь нажимает кнопку "Назад".

Ответ 2

Вы обнаружите, что $locationChangeStart - это событие, которое вы можете прослушивать для обнаружения изменения маршрута.

Попробуйте что-нибудь вроде

$rootScope.$on('$locationChangeStart', function (event, next, current) {
  /* do some verification */
});

$route.reload() предотвратит переход маршрута.

Различие между нажатием кнопки пользователя или изменением URL и т.д. не изменит ситуацию. Поскольку браузеры не перезагружают какие-либо ресурсы, когда вы изменяете URL-адрес, прошедший через #, он все еще содержится в вашей логике angular. Это означает, что все эти методы должны запускать событие $locationChangeStart.

@Jon отметил, что услуга $route определенно будет вам полезна. метод .reload() предотвратит завершение изменения маршрута, но вы можете сделать гораздо больше с помощью службы $route, если вы посмотрите на нее - см. документация.

Ответ 3

Я бы просто сохранил свойство на вашем $rootScope, например hasUnsavedEdits.

function confirmLeavePage(e) {
  var confirmed;
  if ($rootScope.hasUnsavedEdits) {
    confirmed = $window.confirm("You have unsaved edits. Do you wish to leave?");
    if (e && !confirmed) { 
      e.preventDefault();
    }
  }
}

$window.addEventListener('beforeunload', confirmLeavePage);

$rootScope.$on("$locationChangeStart", confirmLeavePage);

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

Ответ 4

Это также хорошая ссылка http://weblogs.asp.net/dwahlin/cancelling-route-navigation-in-angularjs-controllers

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);
}

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;
}

Ответ 5

Я создал следующую службу, которая содержит информацию, указанную в других ответах (CoffeeScript, см. Plunker):

angular.module('myModule').service 'ChangeLossPreventer', ($rootScope, $q, $state) ->

  confirmationMessage = null

  service =
    prevent: (message = 'Changed data will be lost. Continue?') ->
      confirmationMessage = message

    prompt: ->
      confirmation = if confirmationMessage then confirm(confirmationMessage) else yes
      if not confirmation
        $q.reject()
      else
        $q.when(confirmation).then ->
          service.cancel()

    cancel: ->
      confirmationMessage = null

  $rootScope.$on '$stateChangeStart', (event, newState, newStateParams) ->
    if confirmationMessage
      event.preventDefault()
      service.prompt().then ->
        $state.go(newState, newStateParams)

  window.onbeforeunload = ->
    confirmationMessage

  service

Он основан на angular -ui-router (использование службы $state). Когда ваш веб-сайт входит в состояние, в котором данные могут быть потеряны, вам необходимо позвонить

ChangeLossPreventer.prevent("Optional warning message.");

Когда оно существует, это состояние (то есть пользователь сохраняет данные), вам необходимо вызвать:

ChangeLossPreventer.cancel()

По умолчанию предупреждение будет отображаться при изменении состояния или закрытии страницы (например, обновление или переход на другой веб-сайт). Вам также может потребоваться проверить, безопасно ли выполнять другие действия (то есть не выходить из системы с XHR, если есть несохраненные изменения):

$scope.logout = function() {
    // confirmation will pop up only if there are unsaved changes
    ChangeLossPreventer.prompt().then(function(){
       // logout after confirmation
    });
};

Я создал Plunker, который имитирует его.

  • Нажмите текст на главной странице (страница войдет в "небезопасное" состояние).
  • Попробуйте щелкнуть другие ссылки или обновить страницу - должно появиться предупреждение.
  • После "сохранения" поля страница покидает небезопасное состояние, и все работает по-прежнему.

Ответ 6

Для Angular пользователей ES6

export default class myRouteController {

  constructor($scope, $window) {
    this.$scope = $scope;
    this.$window = $window;

    this.$scope.$on('$stateChangeStart', (evt) => {
      if(this.form.$dirty && !$window.confirm('Are you sure you want to leave this page?')) {
        evt.preventDefault();
      }
    });
  }
}