AngularJs - 取消路线更改事件

时间:2013-05-02 17:31:25

标签: javascript angularjs

如何在AngularJs中取消路线更改事件?

我目前的代码是

$rootScope.$on("$routeChangeStart", function (event, next, current) {

// do some validation checks
if(validation checks fails){

    console.log("validation failed");

    window.history.back(); // Cancel Route Change and stay on current page  

}
});

即使验证失败,Angular也会拉出下一个模板和相关数据,然后立即切换回上一个视图/路径。我不希望角度拉下一个模板&如果验证失败,理想情况下应该没有window.history.back()。我甚至尝试过event.preventDefault()但没有用。

9 个答案:

答案 0 :(得分:183)

而不是$routeChangeStart使用$locationChangeStart

以下是来自angularjs家伙的讨论:https://github.com/angular/angular.js/issues/2109

修改3/6/2018 您可以在文档中找到它:https://docs.angularjs.org/api/ng/service/$location#event-$locationChangeStart

示例:

$scope.$on('$locationChangeStart', function(event, next, current) {
    if ($scope.form.$invalid) {
       event.preventDefault();
    }
});

答案 1 :(得分:38)

使用$locationChangeStart

的更完整的代码示例
// assuming you have a module called app, with a 
angular.module('app')
  .controller(
    'MyRootController',
    function($scope, $location, $rootScope, $log) {
      // your controller initialization here ...
      $rootScope.$on("$locationChangeStart", function(event, next, current) { 
        $log.info("location changing to:" + next); 
      });
    }
  );

我对在我的根控制器(顶级控制器)中挂起它并不是很满意。如果有更好的模式,我很想知道。我是棱角分明的新人: - )

答案 2 :(得分:11)

解决方案是播放“未授权”'事件,并在主要范围内捕获它以重新更改位置。我认为这不是最好的解决方案,但它对我有用:

myApp.run(['$rootScope', 'LoginService',
    function ($rootScope, LoginService) {
        $rootScope.$on('$routeChangeStart', function (event, next, current) {
            var authorizedRoles = next.data ? next.data.authorizedRoles : null;
            if (LoginService.isAuthenticated()) {
                if (!LoginService.isAuthorized(authorizedRoles)) {
                    $rootScope.$broadcast('notAuthorized');
                }
            }
        });
    }
]);

并在我的主控制器中:

    $scope.$on('notAuthorized', function(){
        $location.path('/forbidden');
    });

注意:在角点网站上有一些关于这个问题的讨论,还没有解决: https://github.com/angular/angular.js/pull/4192

修改

要回答评论,以下是有关LoginService工作的更多信息。它包含3个功能:

  1. login()(名称具有误导性)向服务器发出请求以获取有关(先前)已登录用户的信息。还有另一个登录页面,它只填充服务器中的当前用户状态(使用SpringSecurity框架)。我的Web服务并非真正的无状态,但我更愿意让这个着名的框架处理我的安全问题。
  2. isAuthenticated()只搜索客户端Session是否填充了数据,这意味着它已经过验证(*)
  3. isAuthorized()处理了访问权限(超出了本主题的范围)。
  4. (*)路线更改时填充我的会话。我已经覆盖了when()方法在空时填充会话。

    以下是代码:

    services.factory('LoginService', ['$http', 'Session', '$q',
    function($http, Session, $q){
        return {
            login: function () {
                var defer = $q.defer();
                $http({method: 'GET', url: restBaseUrl + '/currentUser'})
                    .success(function (data) {
                        defer.resolve(data);
                    });
                return defer.promise;
            },
            isAuthenticated: function () {
                return !!Session.userLogin;
            },
            isAuthorized: function (authorizedRoles) {
                if (!angular.isArray(authorizedRoles)) {
                    authorizedRoles = [authorizedRoles];
                }
    
                return (this.isAuthenticated() &&  authorizedRoles.indexOf(Session.userRole) !== -1);
            }
        };
    }]);
    
    myApp.service('Session', ['$rootScope',
        this.create = function (userId,userLogin, userRole, userMail, userName, userLastName, userLanguage) {
            //User info
            this.userId = userId;
            this.userLogin = userLogin;
            this.userRole = userRole;
            this.userMail = userMail;
            this.userName = userName;
            this.userLastName = userLastName;
            this.userLanguage = userLanguage;
        };
    
        this.destroy = function () {
            this.userId = null;
            this.userLogin = null;
            this.userRole = null;
            this.userMail = null;
            this.userName = null;
            this.userLastName = null;
            this.userLanguage = null;
            sessionStorage.clear();
        };
    
        return this;
    }]);
    
    myApp.config(['$routeProvider', 'USER_ROLES', function ($routeProvider, USER_ROLES) {
        $routeProvider.accessWhen = function (path, route) {
            if (route.resolve == null) {
                route.resolve = {
                    user: ['LoginService','Session',function (LoginService, Session) {
                        if (!LoginService.isAuthenticated())
                            return LoginService.login().then(function (data) {
                                Session.create(data.id, data.login, data.role, data.email, data.firstName, data.lastName, data.language);
                                return data;
                            });
                    }]
                }
            } else {
                for (key in route.resolve) {
                    var func = route.resolve[key];
                    route.resolve[key] = ['LoginService','Session','$injector',function (LoginService, Session, $injector) {
                        if (!LoginService.isAuthenticated())
                            return LoginService.login().then(function (data) {
                                Session.create(data.id, data.login, data.role, data.email, data.firstName, data.lastName, data.language);
                                return func(Session, $injector);
                            });
                        else
                            return func(Session, $injector);
                    }];
                }
            }
        return $routeProvider.when(path, route);
        };
    
        //use accessWhen instead of when
        $routeProvider.
            accessWhen('/home', {
                templateUrl: 'partials/dashboard.html',
                controller: 'DashboardCtrl',
                data: {authorizedRoles: [USER_ROLES.superAdmin, USER_ROLES.admin, USER_ROLES.system, USER_ROLES.user]},
                resolve: {nextEvents: function (Session, $injector) {
                    $http = $injector.get('$http');
                    return $http.get(actionBaseUrl + '/devices/nextEvents', {
                        params: {
                            userId: Session.userId, batch: {rows: 5, page: 1}
                        },
                        isArray: true}).then(function success(response) {
                        return response.data;
                    });
                }
            }
        })
        ...
        .otherwise({
            redirectTo: '/home'
        });
    }]);
    

答案 3 :(得分:4)

对于任何磕磕绊绊的人来说,这是一个古老的问题,(至少在角度1.4中)你可以这样做:

 .run(function($rootScope, authenticationService) {
        $rootScope.$on('$routeChangeStart', function (event, next) {
            if (next.require == undefined) return

            var require = next.require
            var authorized = authenticationService.satisfy(require);

            if (!authorized) {
                $rootScope.error = "Not authorized!"
                event.preventDefault()
            }
        })
      })

答案 4 :(得分:1)

这是我的解决方案,它适用于我,但我不知道我是否正确的方式因为我是网络技术的新手。

var app = angular.module("app", ['ngRoute', 'ngCookies']);
app.run(function($rootScope, $location, $cookieStore){
$rootScope.$on('$routeChangeStart', function(event, route){
    if (route.mustBeLoggedOn && angular.isUndefined($cookieStore.get("user"))) {
        // reload the login route
        jError(
             'You must be logged on to visit this page',
             {
               autoHide : true,
               TimeShown : 3000,
               HorizontalPosition : 'right',
               VerticalPosition : 'top',
               onCompleted : function(){ 
               window.location = '#/signIn';
                 window.setTimeout(function(){

                 }, 3000)
             }
        });
    }
  });
});

app.config(function($routeProvider){
$routeProvider
    .when("/signIn",{
        controller: "SignInController",
        templateUrl: "partials/signIn.html",
        mustBeLoggedOn: false
});

答案 5 :(得分:1)

var app=angular
    .module('myapp', [])
    .controller('myctrl', function($rootScope) {
        $rootScope.$on("locationChangeStart", function(event, next, current) {
        if (!confirm("location changing to:" + next)) { 
            event.preventDefault();
        }
    })
});

答案 6 :(得分:0)

如果你需要停止改变$routeChangeStart事件的路线(即你想根据下一条路线执行一些操作),请注入$route并在$routeChangeStart内调用:

$route.reload()

答案 7 :(得分:0)

我发现了这个相关的

var myApp = angular.module('myApp', []);

myApp.run(function($rootScope) {
    $rootScope.$on("$locationChangeStart", function(event, next, current) { 
        // handle route changes  
$rootScope.error = "Not authorized!"
                event.preventDefault()   
    });
});

我的帖子将来可能对某人有帮助。

答案 8 :(得分:0)

在我的情况下,我只想与$ routeChangeStart共享延迟路由解析。我有一个SomethingService必须在路由解析开始之前加载(是的,健谈的应用程序),因此我有一个等待的保证。也许我发现了一个骇客...如果解决方案返回拒绝,路线的解析就会出错。我破坏了可分辨的配置,以后再修复。

    var rejectingResolve = {
        cancel: function ($q){
            // this will cancel $routeChangeStart
            return $q.reject();
        }
    }
    
    $rootScope.$on("$routeChangeStart", function(event, args, otherArgs) {
        var route = args.$$route,
            originalResolve = route.resolve;
    
        if ( ! SomethingService.isLoaded() ){

            SomethingService.load().then(function(){
                // fix previously destroyed route configuration
                route.resolve = originalResolve;
                
                $location.search("ts", new Date().getTime());
                // for redirections
                $location.replace();
            });

            // This doesn't work with $routeChangeStart: 
            // we need the following hack
            event.preventDefault();
            
            // This is an hack! 
            // We destroy route configuration, 
            // we fix it back when SomethingService.isLoaded
            route.resolve = rejectingResolve;
        } 
    });