AngularJS在路线变更前确认

时间:2013-12-30 21:20:52

标签: javascript angularjs

是否可以监听路由更改并且onwindowunload都可以确认页面休假而不保存更改?

用例:

  • 用户点击Back
  • 用户在浏览器中按下按钮
  • 其他网址中的用户类型

如果用户点击“取消”,请停止更改页面/路线。

我见过几个不同的例子,但都没有做得很好。

6 个答案:

答案 0 :(得分:22)

演示:http://plnkr.co/edit/Aq8uYg

在演示中,如果您更改输入值,则会在尝试返回时注意到。

收听$locationChangeStart,如果未确认更改,请使用event.preventDefault()取消位置更改。

此方法优于$route.reload():当前控制器和模型不会重新实例化。因此,所有变量都与用户单击“返回”按钮保持一致。

答案 1 :(得分:12)

您会发现$locationChangeStart是您可以侦听以检测路线更改的事件。

尝试类似

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

$route.reload()将阻止路线更改。

用户点击或更改网址等之间的区别不会产生影响。由于浏览器在您更改网址#之后不会重新加载任何资源,因此它仍然包含在您的角度逻辑中。这意味着所有这些方法都应该触发$locationChangeStart事件。

@Jon指出$route服务绝对会对您有用。 .reload()方法会阻止路线更改完成,但如果您查看此问题,可以使用$route服务做更多事情 - 请参阅documentation

答案 2 :(得分:4)

我只会在你的$ 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

答案 3 :(得分: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;
}

答案 4 :(得分:0)

我创建了以下服务,其中包含其他答案中提供的信息(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

  1. 点击主页上的文字(页面将输入"不安全"状态)。
  2. 尝试点击其他链接或刷新页面 - 应显示警告。
  3. " save"该字段,页面离开不安全的状态,一切都像以前一样。

答案 5 :(得分:0)

对于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();
      }
    });
  }
}