Javascript AngularJS在路线变更前确认

Javascript AngularJS在路线变更前确认,javascript,angularjs,Javascript,Angularjs,是否可以侦听路由更改和onwindowunload以确认页面离开而不保存更改 用例: 用户点击 用户在浏览器中按下后退按钮 不同URL中的用户类型 如果用户单击“取消”,则停止页面/路线更改 我看到了一些不同的例子,但没有一个是完全正确的。您会发现$locationChangeStart是一个事件,您可以通过监听来检测路由更改 试试像这样的东西 $rootScope.$on('$locationChangeStart', function (event, next, current) {

是否可以侦听路由更改和onwindowunload以确认页面离开而不保存更改

用例:

  • 用户点击
  • 用户在浏览器中按下后退按钮
  • 不同URL中的用户类型
如果用户单击“取消”,则停止页面/路线更改


我看到了一些不同的例子,但没有一个是完全正确的。

您会发现
$locationChangeStart
是一个事件,您可以通过监听来检测路由更改

试试像这样的东西

$rootScope.$on('$locationChangeStart', function (event, next, current) {
  /* do some verification */
});
$route.reload()
将阻止路由更改

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


@乔恩指出,
$route
服务肯定会对你有用。
.reload()
方法将阻止路由更改的完成,但是如果您仔细查看,
$route
服务可以做更多的事情-请参阅。

我只想在$rootScope上维护一个属性,比如
hasunaveddiets

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);
您可能需要稍微调整代码以处理这两种情况。有关详细信息,请参见演示:

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

收听
$locationChangeStart
并使用
event.preventDefault()
在更改未确认时取消位置更改


$route.reload()
相比,此方法有一个优点:当前控制器和模型不会重新实例化。因此,当用户单击“后退”按钮时,所有变量都保持不变。

我创建了以下服务,其中包含了其他答案中给出的信息(CoffeeScript,请参阅):

它基于angular ui路由器(使用
$state
服务)。当您的网站进入数据可能丢失的状态时,您需要拨打

ChangeLossPreventer.prevent("Optional warning message.");
如果存在此状态(即用户保存数据),则需要调用:

ChangeLossPreventer.cancel()
默认情况下,警告将出现在状态更改或页面关闭时(即刷新或转到其他网站)。您可能还需要验证执行其他操作是否安全(即,如果存在未保存的更改,则不要使用XHR注销):

我已经创建了一个模拟它的

  • 单击主页上的文本(页面将进入“不安全”状态)
  • 尝试单击其他链接或刷新页面-应显示警告
  • 在“保存”字段后,页面将离开不安全状态,所有操作都与以前一样
  • 这也是一个不错的链接

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

    一定要退房。。您可能希望利用某些事件。@LawerenceJones一些注意事项:$route.reload()不会停止页面更改。当在浏览器中键入其他url时,这不起作用,我想我也需要执行
    onunload
    。您确定只编辑url中超出
    #
    的部分吗?我现在已经在chrome上测试了它,它在那个事件中得到了提升。我应该澄清,
    $route.reload
    只会重新加载当前路由,因此首先会阻止路由更改。另外,仅供参考-我发现$routeChangeStart是不可取消的,+1表示$locationChangeStart这也不会阻止页面更改。具体是什么不起作用?
    confirmLeavePage
    是否点火?$window.confirm是否会弹出一条消息?如果我执行类似以下操作会怎么样:
    $location.path('config/'+$routeParams.id)
    这仍然有效吗?@amcdnl我没有尝试,但您可以通过将锚定标记的
    herf
    更改为
    ng单击
    并重试来测试它。当用户使用ui sref指令单击锚定时,这不适用于我的情况。在这种情况下,locationChangeStart是在状态更改后触发的。
    $scope.logout = function() {
        // confirmation will pop up only if there are unsaved changes
        ChangeLossPreventer.prompt().then(function(){
           // logout after confirmation
        });
    };
    
    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;
    }
    
    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();
          }
        });
      }
    }